diff --git a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/DbiStream.cs b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/DbiStream.cs index 9744d852e..e9180fb4d 100644 --- a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/DbiStream.cs +++ b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/DbiStream.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Threading; using AsmResolver.IO; using AsmResolver.PE.File.Headers; @@ -18,8 +20,8 @@ public class DbiStream : SegmentBase private IList? _modules; private IList? _sectionContributions; private IList? _sectionMaps; - private readonly LazyVariable _typeServerMapStream; - private readonly LazyVariable _ecStream; + private readonly LazyVariable _typeServerMapStream; + private readonly LazyVariable _ecStream; private IList? _sourceFiles; private IList? _extraStreamIndices; @@ -28,8 +30,8 @@ public class DbiStream : SegmentBase /// public DbiStream() { - _typeServerMapStream = new LazyVariable(GetTypeServerMapStream); - _ecStream = new LazyVariable(GetECStream); + _typeServerMapStream = new LazyVariable(GetTypeServerMapStream); + _ecStream = new LazyVariable(GetECStream); } /// @@ -196,7 +198,7 @@ public IList SectionMaps /// The exact purpose and layout of this sub stream is unknown, hence this property exposes the stream as /// a raw segment. /// - public ISegment TypeServerMapStream + public ISegment? TypeServerMapStream { get => _typeServerMapStream.Value; set => _typeServerMapStream.Value = value; @@ -209,7 +211,7 @@ public ISegment TypeServerMapStream /// The exact purpose and layout of this sub stream is unknown, hence this property exposes the stream as /// a raw segment. /// - public ISegment ECStream + public ISegment? ECStream { get => _ecStream.Value; set => _ecStream.Value = value; @@ -319,12 +321,247 @@ public IList ExtraStreamIndices /// public override uint GetPhysicalSize() { - throw new System.NotImplementedException(); + return GetHeaderSize() + + GetModuleStreamSize() + + GetSectionContributionStreamSize() + + GetSectionMapStreamSize() + + GetSourceInfoStreamSize() + + GetTypeServerMapStreamSize() + + GetECStreamSize() + + GetOptionalDebugStreamSize() + ; + } + + private static uint GetHeaderSize() + { + return sizeof(int) // VersionSignature + + sizeof(DbiStreamVersion) // VersionHeader + + sizeof(uint) // Age + + sizeof(ushort) // GlobalStreamIndex + + sizeof(ushort) // BuildNumber + + sizeof(ushort) // PublicStreamIndex + + sizeof(ushort) // PdbDllVersion + + sizeof(ushort) // SymbolRecordStreamIndex + + sizeof(ushort) // PdbDllRbld + + sizeof(uint) // ModuleInfoSize + + sizeof(uint) // SectionContributionSize + + sizeof(uint) // SectionMapSize + + sizeof(uint) // SourceInfoSize + + sizeof(uint) // TypeServerMapSize + + sizeof(uint) // MfcTypeServerIndex + + sizeof(uint) // OptionalDebugStreamSize + + sizeof(uint) // ECStreamSize + + sizeof(DbiAttributes) // Attributes + + sizeof(MachineType) // MachineType + + sizeof(uint) // Padding + ; + } + + private uint GetModuleStreamSize() + { + return ((uint) Modules.Sum(m => m.GetPhysicalSize())).Align(sizeof(uint)); + } + + private uint GetSectionContributionStreamSize() + { + return sizeof(uint) // version + + SectionContribution.EntrySize * (uint) SectionContributions.Count; + } + + private uint GetSectionMapStreamSize() + { + return sizeof(ushort) // Count + + sizeof(ushort) // LogCount + + SectionMap.EntrySize * (uint) SectionMaps.Count; + } + + private uint GetSourceInfoStreamSize() + { + uint totalFileCount = 0; + uint nameBufferSize = 0; + var stringOffsets = new Dictionary(); + + // Simulate the construction of name buffer + for (int i = 0; i < SourceFiles.Count; i++) + { + var collection = SourceFiles[i]; + totalFileCount += (uint) collection.Count; + + for (int j = 0; j < collection.Count; j++) + { + // If name is not added yet, "append" to the name buffer. + var name = collection[j]; + if (!stringOffsets.ContainsKey(name)) + { + stringOffsets[name] = nameBufferSize; + nameBufferSize += (uint) name.ByteCount + 1u; + } + } + } + + return (sizeof(ushort) // ModuleCount + + sizeof(ushort) // SourceFileCount + + sizeof(ushort) * (uint) SourceFiles.Count // ModuleIndices + + sizeof(ushort) * (uint) SourceFiles.Count // SourceFileCounts + + sizeof(uint) * totalFileCount // NameOffsets + + nameBufferSize // NameBuffer + ).Align(4); + } + + private uint GetTypeServerMapStreamSize() + { + return TypeServerMapStream?.GetPhysicalSize().Align(sizeof(uint)) ?? 0u; + } + + private uint GetOptionalDebugStreamSize() + { + return (uint) (ExtraStreamIndices.Count * sizeof(ushort)); + } + + private uint GetECStreamSize() + { + return ECStream?.GetPhysicalSize() ?? 0u; } /// public override void Write(IBinaryStreamWriter writer) { - throw new System.NotImplementedException(); + WriteHeader(writer); + WriteModuleStream(writer); + WriteSectionContributionStream(writer); + WriteSectionMapStream(writer); + WriteSourceInfoStream(writer); + WriteTypeServerMapStream(writer); + WriteECStream(writer); + WriteOptionalDebugStream(writer); + } + + private void WriteHeader(IBinaryStreamWriter writer) + { + writer.WriteInt32(VersionSignature); + writer.WriteUInt32((uint) VersionHeader); + writer.WriteUInt32(Age); + writer.WriteUInt16(GlobalStreamIndex); + writer.WriteUInt16(BuildNumber); + writer.WriteUInt16(PublicStreamIndex); + writer.WriteUInt16(PdbDllVersion); + writer.WriteUInt16(SymbolRecordStreamIndex); + writer.WriteUInt16(PdbDllRbld); + + writer.WriteUInt32(GetModuleStreamSize()); + writer.WriteUInt32(GetSectionContributionStreamSize()); + writer.WriteUInt32(GetSectionMapStreamSize()); + writer.WriteUInt32(GetSourceInfoStreamSize()); + writer.WriteUInt32(GetTypeServerMapStreamSize()); + + writer.WriteUInt32(MfcTypeServerIndex); + + writer.WriteUInt32(GetOptionalDebugStreamSize()); + writer.WriteUInt32(GetECStreamSize()); + + writer.WriteUInt16((ushort) Attributes); + writer.WriteUInt16((ushort) Machine); + + writer.WriteUInt32(0); + } + + private void WriteModuleStream(IBinaryStreamWriter writer) + { + var modules = Modules; + for (int i = 0; i < modules.Count; i++) + modules[i].Write(writer); + + writer.Align(sizeof(uint)); } + + private void WriteSectionContributionStream(IBinaryStreamWriter writer) + { + // TODO: make customizable + writer.WriteUInt32((uint) SectionContributionStreamVersion.Ver60); + + var contributions = SectionContributions; + for (int i = 0; i < contributions.Count; i++) + contributions[i].Write(writer); + + writer.Align(sizeof(uint)); + } + + private void WriteSectionMapStream(IBinaryStreamWriter writer) + { + var maps = SectionMaps; + + // Count and LogCount. + writer.WriteUInt16((ushort) maps.Count); + writer.WriteUInt16((ushort) maps.Count); + + // Entries. + for (int i = 0; i < maps.Count; i++) + maps[i].Write(writer); + + writer.Align(sizeof(uint)); + } + + private void WriteSourceInfoStream(IBinaryStreamWriter writer) + { + var sourceFiles = SourceFiles; + int totalFileCount = sourceFiles.Sum(x => x.Count); + + // Module and total file count (truncated to 16 bits) + writer.WriteUInt16((ushort) (sourceFiles.Count & 0xFFFF)); + writer.WriteUInt16((ushort) (totalFileCount & 0xFFFF)); + + // Module indices. Unsure if this is correct, but this array does not seem to be really used by the ref impl. + for (ushort i = 0; i < sourceFiles.Count; i++) + writer.WriteUInt16(i); + + // Source file counts. + for (int i = 0; i < sourceFiles.Count; i++) + writer.WriteUInt16((ushort) sourceFiles[i].Count); + + // Build up string buffer and name offset table. + using var stringBuffer = new MemoryStream(); + var stringWriter = new BinaryStreamWriter(stringBuffer); + var stringOffsets = new Dictionary(); + + for (int i = 0; i < sourceFiles.Count; i++) + { + var collection = sourceFiles[i]; + for (int j = 0; j < collection.Count; j++) + { + // If not present already, append to string buffer. + var name = collection[j]; + if (!stringOffsets.TryGetValue(name, out uint offset)) + { + offset = (uint) stringWriter.Offset; + stringOffsets[name] = offset; + stringWriter.WriteBytes(name.GetBytesUnsafe()); + stringWriter.WriteByte(0); + } + + // Write name offset + writer.WriteUInt32(offset); + } + } + + // Write string buffer. + writer.WriteBytes(stringBuffer.ToArray()); + + writer.Align(sizeof(uint)); + } + + private void WriteTypeServerMapStream(IBinaryStreamWriter writer) + { + TypeServerMapStream?.Write(writer); + writer.Align(sizeof(uint)); + } + + private void WriteOptionalDebugStream(IBinaryStreamWriter writer) + { + var extraIndices = ExtraStreamIndices; + + for (int i = 0; i < extraIndices.Count; i++) + writer.WriteUInt16(extraIndices[i]); + } + + private void WriteECStream(IBinaryStreamWriter writer) => ECStream?.Write(writer); } diff --git a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/ModuleDescriptor.cs b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/ModuleDescriptor.cs index 968777a1d..5fee61c3e 100644 --- a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/ModuleDescriptor.cs +++ b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/ModuleDescriptor.cs @@ -1,207 +1,207 @@ -using AsmResolver.IO; - -namespace AsmResolver.Symbols.Pdb.Metadata.Dbi; - -/// -/// Represents a reference to a single module (object file) that was linked into a program. -/// -public class ModuleDescriptor : IWritable -{ - /// - /// Gets or sets a description of the section within the final binary which contains code - /// and/or data from this module. - /// - public SectionContribution SectionContribution - { - get; - set; - } = new(); - - /// - /// Gets or sets the attributes assigned to this module descriptor. - /// - public ModuleDescriptorAttributes Attributes - { - get; - set; - } - - /// - /// Gets or sets the index of the type server for this module. - /// - public ushort TypeServerIndex - { - get => (ushort) ((ushort) Attributes >> 8); - set => Attributes = (Attributes & ~ModuleDescriptorAttributes.TsmMask) | (ModuleDescriptorAttributes) (value << 8); - } - - /// - /// Gets or sets the MSF stream index of the stream that the symbols of this module. - /// - public ushort SymbolStreamIndex - { - get; - set; - } - - /// - /// Gets or sets the size of the CodeView data within the module's symbol stream. - /// - public uint SymbolDataSize - { - get; - set; - } - - /// - /// Gets or sets the size of the C11-style CodeView data within the module's symbol stream. - /// - public uint SymbolC11DataSize - { - get; - set; - } - - /// - /// Gets or sets the size of the C13-style CodeView data within the module's symbol stream. - /// - public uint SymbolC13DataSize - { - get; - set; - } - - /// - /// Gets or sets the number of source files that contributed to this module during the compilation. - /// - public ushort SourceFileCount - { - get; - set; - } - - /// - /// Gets or sets the offset in the names buffer of the primary translation unit. - /// - /// - /// For most compilers this value is set to zero. - /// - public uint SourceFileNameIndex - { - get; - set; - } - - /// - /// Gets or sets the offset in the names buffer of the PDB file. - /// - /// - /// For most modules (except the special * LINKER * module) this value is set to zero. - /// - public uint PdbFilePathNameIndex - { - get; - set; - } - - /// - /// Gets or sets the name of the module. - /// - /// - /// This is often a full path to the object file that was passed into link.exe directly, or a string in the - /// form of Import:dll_name - /// - public Utf8String? ModuleName - { - get; - set; - } - - /// - /// Gets or sets the name of the object file name. - /// - /// - /// In the case this module is linked directly passed to link.exe, this is the same as . - /// If the module comes from an archive, this is the full path to that archive. - /// - public Utf8String? ObjectFileName - { - get; - set; - } - - /// - /// Parses a single module descriptor from the provided input stream. - /// - /// The input stream. - /// THe parsed module descriptor. - public static ModuleDescriptor FromReader(ref BinaryStreamReader reader) - { - var result = new ModuleDescriptor(); - - reader.ReadUInt32(); - result.SectionContribution = SectionContribution.FromReader(ref reader); - result.Attributes = (ModuleDescriptorAttributes) reader.ReadUInt16(); - result.SymbolStreamIndex = reader.ReadUInt16(); - result.SymbolDataSize = reader.ReadUInt32(); - result.SymbolC11DataSize = reader.ReadUInt32(); - result.SymbolC13DataSize = reader.ReadUInt32(); - result.SourceFileCount = reader.ReadUInt16(); - reader.ReadUInt16(); - reader.ReadUInt32(); - result.SourceFileNameIndex = reader.ReadUInt32(); - result.PdbFilePathNameIndex = reader.ReadUInt32(); - result.ModuleName = new Utf8String(reader.ReadBytesUntil(0, false)); - result.ObjectFileName = new Utf8String(reader.ReadBytesUntil(0, false)); - reader.Align(4); - - return result; - } - - /// - public uint GetPhysicalSize() - { - return sizeof(uint) // Unused1 - + SectionContribution.GetPhysicalSize() // SectionContribution - + sizeof(ModuleDescriptorAttributes) // Attributes - + sizeof(ushort) // SymbolStreamIndex - + sizeof(uint) // SymbolDataSize - + sizeof(uint) // SymbolC11DataSize - + sizeof(uint) // SymbolC13DataSize - + sizeof(ushort) // SourceFileCount - + sizeof(char) * 2 // Padding - + sizeof(uint) // Unused2 - + sizeof(uint) // SourceFileNameIndex - + sizeof(uint) // PdbFilePathNameIndex - + (uint) (ModuleName?.ByteCount ?? 0) + 1 // ModuleName - + (uint) (ObjectFileName?.ByteCount ?? 0) + 1 // ObjectFileName - ; - } - - /// - public void Write(IBinaryStreamWriter writer) - { - writer.WriteUInt32(0); - SectionContribution.Write(writer); - writer.WriteUInt16((ushort) Attributes); - writer.WriteUInt16(SymbolStreamIndex); - writer.WriteUInt32(SymbolDataSize); - writer.WriteUInt32(SymbolC11DataSize); - writer.WriteUInt32(SymbolC13DataSize); - writer.WriteUInt16(SourceFileCount); - writer.WriteUInt16(0); - writer.WriteUInt32(0); - writer.WriteUInt32(SourceFileNameIndex); - writer.WriteUInt32(PdbFilePathNameIndex); - if (ModuleName is not null) - writer.WriteBytes(ModuleName.GetBytesUnsafe()); - writer.WriteByte(0); - if (ObjectFileName is not null) - writer.WriteBytes(ObjectFileName.GetBytesUnsafe()); - writer.WriteByte(0); - writer.Align(4); - } - - /// - public override string ToString() => ModuleName ?? ObjectFileName ?? "?"; -} +using AsmResolver.IO; + +namespace AsmResolver.Symbols.Pdb.Metadata.Dbi; + +/// +/// Represents a reference to a single module (object file) that was linked into a program. +/// +public class ModuleDescriptor : IWritable +{ + /// + /// Gets or sets a description of the section within the final binary which contains code + /// and/or data from this module. + /// + public SectionContribution SectionContribution + { + get; + set; + } = new(); + + /// + /// Gets or sets the attributes assigned to this module descriptor. + /// + public ModuleDescriptorAttributes Attributes + { + get; + set; + } + + /// + /// Gets or sets the index of the type server for this module. + /// + public ushort TypeServerIndex + { + get => (ushort) ((ushort) Attributes >> 8); + set => Attributes = (Attributes & ~ModuleDescriptorAttributes.TsmMask) | (ModuleDescriptorAttributes) (value << 8); + } + + /// + /// Gets or sets the MSF stream index of the stream that the symbols of this module. + /// + public ushort SymbolStreamIndex + { + get; + set; + } + + /// + /// Gets or sets the size of the CodeView data within the module's symbol stream. + /// + public uint SymbolDataSize + { + get; + set; + } + + /// + /// Gets or sets the size of the C11-style CodeView data within the module's symbol stream. + /// + public uint SymbolC11DataSize + { + get; + set; + } + + /// + /// Gets or sets the size of the C13-style CodeView data within the module's symbol stream. + /// + public uint SymbolC13DataSize + { + get; + set; + } + + /// + /// Gets or sets the number of source files that contributed to this module during the compilation. + /// + public ushort SourceFileCount + { + get; + set; + } + + /// + /// Gets or sets the offset in the names buffer of the primary translation unit. + /// + /// + /// For most compilers this value is set to zero. + /// + public uint SourceFileNameIndex + { + get; + set; + } + + /// + /// Gets or sets the offset in the names buffer of the PDB file. + /// + /// + /// For most modules (except the special * LINKER * module) this value is set to zero. + /// + public uint PdbFilePathNameIndex + { + get; + set; + } + + /// + /// Gets or sets the name of the module. + /// + /// + /// This is often a full path to the object file that was passed into link.exe directly, or a string in the + /// form of Import:dll_name + /// + public Utf8String? ModuleName + { + get; + set; + } + + /// + /// Gets or sets the name of the object file name. + /// + /// + /// In the case this module is linked directly passed to link.exe, this is the same as . + /// If the module comes from an archive, this is the full path to that archive. + /// + public Utf8String? ObjectFileName + { + get; + set; + } + + /// + /// Parses a single module descriptor from the provided input stream. + /// + /// The input stream. + /// THe parsed module descriptor. + public static ModuleDescriptor FromReader(ref BinaryStreamReader reader) + { + var result = new ModuleDescriptor(); + + reader.ReadUInt32(); + result.SectionContribution = SectionContribution.FromReader(ref reader); + result.Attributes = (ModuleDescriptorAttributes) reader.ReadUInt16(); + result.SymbolStreamIndex = reader.ReadUInt16(); + result.SymbolDataSize = reader.ReadUInt32(); + result.SymbolC11DataSize = reader.ReadUInt32(); + result.SymbolC13DataSize = reader.ReadUInt32(); + result.SourceFileCount = reader.ReadUInt16(); + reader.ReadUInt16(); + reader.ReadUInt32(); + result.SourceFileNameIndex = reader.ReadUInt32(); + result.PdbFilePathNameIndex = reader.ReadUInt32(); + result.ModuleName = new Utf8String(reader.ReadBytesUntil(0, false)); + result.ObjectFileName = new Utf8String(reader.ReadBytesUntil(0, false)); + reader.Align(4); + + return result; + } + + /// + public uint GetPhysicalSize() + { + return (sizeof(uint) // Unused1 + + SectionContribution.GetPhysicalSize() // SectionContribution + + sizeof(ModuleDescriptorAttributes) // Attributes + + sizeof(ushort) // SymbolStreamIndex + + sizeof(uint) // SymbolDataSize + + sizeof(uint) // SymbolC11DataSize + + sizeof(uint) // SymbolC13DataSize + + sizeof(ushort) // SourceFileCount + + sizeof(ushort) // Padding + + sizeof(uint) // Unused2 + + sizeof(uint) // SourceFileNameIndex + + sizeof(uint) // PdbFilePathNameIndex + + (uint) (ModuleName?.ByteCount ?? 0) + 1 // ModuleName + + (uint) (ObjectFileName?.ByteCount ?? 0) + 1 // ObjectFileName + ).Align(4); + } + + /// + public void Write(IBinaryStreamWriter writer) + { + writer.WriteUInt32(0); + SectionContribution.Write(writer); + writer.WriteUInt16((ushort) Attributes); + writer.WriteUInt16(SymbolStreamIndex); + writer.WriteUInt32(SymbolDataSize); + writer.WriteUInt32(SymbolC11DataSize); + writer.WriteUInt32(SymbolC13DataSize); + writer.WriteUInt16(SourceFileCount); + writer.WriteUInt16(0); + writer.WriteUInt32(0); + writer.WriteUInt32(SourceFileNameIndex); + writer.WriteUInt32(PdbFilePathNameIndex); + if (ModuleName is not null) + writer.WriteBytes(ModuleName.GetBytesUnsafe()); + writer.WriteByte(0); + if (ObjectFileName is not null) + writer.WriteBytes(ObjectFileName.GetBytesUnsafe()); + writer.WriteByte(0); + writer.Align(4); + } + + /// + public override string ToString() => ModuleName ?? ObjectFileName ?? "?"; +} diff --git a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionContribution.cs b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionContribution.cs index 35953c208..83daaae3e 100644 --- a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionContribution.cs +++ b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionContribution.cs @@ -1,125 +1,128 @@ -using System.Text; -using AsmResolver.IO; -using AsmResolver.PE.File.Headers; - -namespace AsmResolver.Symbols.Pdb.Metadata.Dbi; - -/// -/// Describes the section in the final executable file that a particular object or module is stored at. -/// -public class SectionContribution : IWritable -{ - /// - /// Gets or sets the index of the section. - /// - public ushort Section - { - get; - set; - } - - /// - /// Gets or sets the offset within the section that this contribution starts at. - /// - public uint Offset - { - get; - set; - } - - /// - /// Gets or sets the size of the section contribution. - /// - public uint Size - { - get; - set; - } - - /// - /// Gets or sets the section flags and permissions associated to this section contribution. - /// - public SectionFlags Characteristics - { - get; - set; - } - - /// - /// Gets or sets the index of the module. - /// - public ushort ModuleIndex - { - get; - set; - } - - /// - /// Gets or sets a cyclic redundancy code that can be used to verify the data section of this contribution. - /// - public uint DataCrc - { - get; - set; - } - - /// - /// Gets or sets a cyclic redundancy code that can be used to verify the relocation section of this contribution. - /// - public uint RelocCrc - { - get; - set; - } - - /// - /// Parses a single section contribution from the provided input stream. - /// - /// The input stream. - /// The parsed section contribution. - public static SectionContribution FromReader(ref BinaryStreamReader reader) - { - var result = new SectionContribution(); - - result.Section = reader.ReadUInt16(); - reader.ReadUInt16(); - result.Offset = reader.ReadUInt32(); - result.Size = reader.ReadUInt32(); - result.Characteristics = (SectionFlags) reader.ReadUInt32(); - result.ModuleIndex = reader.ReadUInt16(); - reader.ReadUInt16(); - result.DataCrc = reader.ReadUInt32(); - result.RelocCrc = reader.ReadUInt32(); - - return result; - } - - /// - public uint GetPhysicalSize() - { - return sizeof(ushort) // Section - + sizeof(ushort) // Padding1 - + sizeof(uint) // Offset - + sizeof(uint) // Size - + sizeof(uint) // Characteristics - + sizeof(ushort) // ModuleIndex - + sizeof(ushort) // Padding2 - + sizeof(uint) // DataCrc - + sizeof(uint) // RelocCrc - ; - } - - /// - public void Write(IBinaryStreamWriter writer) - { - writer.WriteUInt16(Section); - writer.WriteUInt16(0); - writer.WriteUInt32(Offset); - writer.WriteUInt32(Size); - writer.WriteUInt32((uint) Characteristics); - writer.WriteUInt16(ModuleIndex); - writer.WriteUInt16(0); - writer.WriteUInt32(DataCrc); - writer.WriteUInt32(RelocCrc); - } -} +using System.Text; +using AsmResolver.IO; +using AsmResolver.PE.File.Headers; + +namespace AsmResolver.Symbols.Pdb.Metadata.Dbi; + +/// +/// Describes the section in the final executable file that a particular object or module is stored at. +/// +public class SectionContribution : IWritable +{ + /// + /// The total size in bytes of a single on the disk. + /// + public const int EntrySize = + sizeof(ushort) // Section + + sizeof(ushort) // Padding1 + + sizeof(uint) // Offset + + sizeof(uint) // Size + + sizeof(uint) // Characteristics + + sizeof(ushort) // ModuleIndex + + sizeof(ushort) // Padding2 + + sizeof(uint) // DataCrc + + sizeof(uint) // RelocCrc + ; + + /// + /// Gets or sets the index of the section. + /// + public ushort Section + { + get; + set; + } + + /// + /// Gets or sets the offset within the section that this contribution starts at. + /// + public uint Offset + { + get; + set; + } + + /// + /// Gets or sets the size of the section contribution. + /// + public uint Size + { + get; + set; + } + + /// + /// Gets or sets the section flags and permissions associated to this section contribution. + /// + public SectionFlags Characteristics + { + get; + set; + } + + /// + /// Gets or sets the index of the module. + /// + public ushort ModuleIndex + { + get; + set; + } + + /// + /// Gets or sets a cyclic redundancy code that can be used to verify the data section of this contribution. + /// + public uint DataCrc + { + get; + set; + } + + /// + /// Gets or sets a cyclic redundancy code that can be used to verify the relocation section of this contribution. + /// + public uint RelocCrc + { + get; + set; + } + + /// + /// Parses a single section contribution from the provided input stream. + /// + /// The input stream. + /// The parsed section contribution. + public static SectionContribution FromReader(ref BinaryStreamReader reader) + { + var result = new SectionContribution(); + + result.Section = reader.ReadUInt16(); + reader.ReadUInt16(); + result.Offset = reader.ReadUInt32(); + result.Size = reader.ReadUInt32(); + result.Characteristics = (SectionFlags) reader.ReadUInt32(); + result.ModuleIndex = reader.ReadUInt16(); + reader.ReadUInt16(); + result.DataCrc = reader.ReadUInt32(); + result.RelocCrc = reader.ReadUInt32(); + + return result; + } + + /// + public uint GetPhysicalSize() => EntrySize; + + /// + public void Write(IBinaryStreamWriter writer) + { + writer.WriteUInt16(Section); + writer.WriteUInt16(0); + writer.WriteUInt32(Offset); + writer.WriteUInt32(Size); + writer.WriteUInt32((uint) Characteristics); + writer.WriteUInt16(ModuleIndex); + writer.WriteUInt16(0); + writer.WriteUInt32(DataCrc); + writer.WriteUInt32(RelocCrc); + } +} diff --git a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionMap.cs b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionMap.cs index 6c42bb300..bf43a7e56 100644 --- a/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionMap.cs +++ b/src/AsmResolver.Symbols.Pdb/Metadata/Dbi/SectionMap.cs @@ -1,128 +1,131 @@ -using AsmResolver.IO; - -namespace AsmResolver.Symbols.Pdb.Metadata.Dbi; - -/// -/// Represents a single entry in the Section Map sub stream of the DBI stream. -/// -public class SectionMap : IWritable -{ - /// - /// Gets or sets the attributes assigned to this section map. - /// - public SectionMapAttributes Attributes - { - get; - set; - } - - /// - /// Gets or sets the logical overlay number of this section map. - /// - public ushort LogicalOverlayNumber - { - get; - set; - } - - /// - /// Gets or sets the group index into the descriptor array. - /// - public ushort Group - { - get; - set; - } - - /// - /// Gets or sets the frame index. - /// - public ushort Frame - { - get; - set; - } - - /// - /// Gets or sets the byte offset of the segment or group name in string table, or 0xFFFF if no name was assigned. - /// - public ushort SectionName - { - get; - set; - } - - /// - /// Gets or sets the byte offset of the class in the string table, or 0xFFFF if no name was assigned.. - /// - public ushort ClassName - { - get; - set; - } - - /// - /// Gets or sets the byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group. - /// - public uint Offset - { - get; - set; - } - - /// - /// Gets or sets the number of bytes that the segment or group consists of. - /// - public uint SectionLength - { - get; - set; - } - - /// - /// Parses a single section map from the provided input stream. - /// - /// The input stream. - /// The parsed section map. - public static SectionMap FromReader(ref BinaryStreamReader reader) - { - return new SectionMap - { - Attributes = (SectionMapAttributes) reader.ReadUInt16(), - LogicalOverlayNumber = reader.ReadUInt16(), - Group = reader.ReadUInt16(), - Frame = reader.ReadUInt16(), - SectionName = reader.ReadUInt16(), - ClassName = reader.ReadUInt16(), - Offset = reader.ReadUInt32(), - SectionLength = reader.ReadUInt32() - }; - } - - /// - public uint GetPhysicalSize() - { - return sizeof(ushort) // Attributes - + sizeof(ushort) // Ovl - + sizeof(ushort) // Group - + sizeof(ushort) // Frame - + sizeof(ushort) // SectionName - + sizeof(ushort) // ClassName - + sizeof(uint) // Offset - + sizeof(uint) // SectionLength - ; - } - - /// - public void Write(IBinaryStreamWriter writer) - { - writer.WriteUInt16((ushort) Attributes); - writer.WriteUInt16(LogicalOverlayNumber); - writer.WriteUInt16(Group); - writer.WriteUInt16(Frame); - writer.WriteUInt16(SectionName); - writer.WriteUInt16(ClassName); - writer.WriteUInt32(Offset); - writer.WriteUInt32(SectionLength); - } -} +using AsmResolver.IO; + +namespace AsmResolver.Symbols.Pdb.Metadata.Dbi; + +/// +/// Represents a single entry in the Section Map sub stream of the DBI stream. +/// +public class SectionMap : IWritable +{ + /// + /// The total size in bytes of a single on the disk. + /// + public const int EntrySize = + sizeof(ushort) // Attributes + + sizeof(ushort) // Ovl + + sizeof(ushort) // Group + + sizeof(ushort) // Frame + + sizeof(ushort) // SectionName + + sizeof(ushort) // ClassName + + sizeof(uint) // Offset + + sizeof(uint) // SectionLength + ; + + /// + /// Gets or sets the attributes assigned to this section map. + /// + public SectionMapAttributes Attributes + { + get; + set; + } + + /// + /// Gets or sets the logical overlay number of this section map. + /// + public ushort LogicalOverlayNumber + { + get; + set; + } + + /// + /// Gets or sets the group index into the descriptor array. + /// + public ushort Group + { + get; + set; + } + + /// + /// Gets or sets the frame index. + /// + public ushort Frame + { + get; + set; + } + + /// + /// Gets or sets the byte offset of the segment or group name in string table, or 0xFFFF if no name was assigned. + /// + public ushort SectionName + { + get; + set; + } + + /// + /// Gets or sets the byte offset of the class in the string table, or 0xFFFF if no name was assigned.. + /// + public ushort ClassName + { + get; + set; + } + + /// + /// Gets or sets the byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group. + /// + public uint Offset + { + get; + set; + } + + /// + /// Gets or sets the number of bytes that the segment or group consists of. + /// + public uint SectionLength + { + get; + set; + } + + /// + /// Parses a single section map from the provided input stream. + /// + /// The input stream. + /// The parsed section map. + public static SectionMap FromReader(ref BinaryStreamReader reader) + { + return new SectionMap + { + Attributes = (SectionMapAttributes) reader.ReadUInt16(), + LogicalOverlayNumber = reader.ReadUInt16(), + Group = reader.ReadUInt16(), + Frame = reader.ReadUInt16(), + SectionName = reader.ReadUInt16(), + ClassName = reader.ReadUInt16(), + Offset = reader.ReadUInt32(), + SectionLength = reader.ReadUInt32() + }; + } + + /// + public uint GetPhysicalSize() => EntrySize; + + /// + public void Write(IBinaryStreamWriter writer) + { + writer.WriteUInt16((ushort) Attributes); + writer.WriteUInt16(LogicalOverlayNumber); + writer.WriteUInt16(Group); + writer.WriteUInt16(Frame); + writer.WriteUInt16(SectionName); + writer.WriteUInt16(ClassName); + writer.WriteUInt32(Offset); + writer.WriteUInt32(SectionLength); + } +} diff --git a/test/AsmResolver.Symbols.Pdb.Tests/Metadata/Dbi/DbiStreamTest.cs b/test/AsmResolver.Symbols.Pdb.Tests/Metadata/Dbi/DbiStreamTest.cs index 179173850..33fbba2bc 100644 --- a/test/AsmResolver.Symbols.Pdb.Tests/Metadata/Dbi/DbiStreamTest.cs +++ b/test/AsmResolver.Symbols.Pdb.Tests/Metadata/Dbi/DbiStreamTest.cs @@ -1,172 +1,200 @@ -using System; -using System.Linq; -using AsmResolver.PE.File.Headers; -using AsmResolver.Symbols.Pdb.Metadata.Dbi; -using AsmResolver.Symbols.Pdb.Msf; -using Xunit; - -namespace AsmResolver.Symbols.Pdb.Tests.Metadata.Dbi; - -public class DbiStreamTest -{ - [Fact] - public void ReadHeader() - { - var file = MsfFile.FromBytes(Properties.Resources.SimpleDllPdb); - var dbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader()); - - Assert.Equal(1u, dbiStream.Age); - Assert.Equal(DbiAttributes.None, dbiStream.Attributes); - Assert.Equal(MachineType.I386, dbiStream.Machine); - } - - [Fact] - public void ReadModuleNames() - { - var file = MsfFile.FromBytes(Properties.Resources.SimpleDllPdb); - var dbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader()); - - Assert.Equal(new[] - { - "* CIL *", - "C:\\Users\\Admin\\source\\repos\\AsmResolver\\test\\TestBinaries\\Native\\SimpleDll\\Release\\dllmain.obj", - "C:\\Users\\Admin\\source\\repos\\AsmResolver\\test\\TestBinaries\\Native\\SimpleDll\\Release\\pch.obj", - "* Linker Generated Manifest RES *", - "Import:KERNEL32.dll", - "KERNEL32.dll", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\sehprolg4.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\gs_cookie.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\gs_report.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\gs_support.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\guard_support.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\loadcfg.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\dyn_tls_init.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\ucrt_detection.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\cpu_disp.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\chandler4gs.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\secchk.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\argv_mode.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\default_local_stdio_options.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\tncleanup.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\dll_dllmain.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\initializers.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\utility.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\ucrt_stubs.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\utility_desktop.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\initsect.obj", - "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\x86_exception_filter.obj", - "VCRUNTIME140.dll", - "Import:VCRUNTIME140.dll", - "Import:api-ms-win-crt-runtime-l1-1-0.dll", - "api-ms-win-crt-runtime-l1-1-0.dll", - "* Linker *", - }, dbiStream.Modules.Select(m => m.ModuleName?.Value)); - } - - [Fact] - public void ReadSectionContributions() - { - var file = MsfFile.FromBytes(Properties.Resources.SimpleDllPdb); - var dbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader()); - - Assert.Equal(new (ushort, uint)[] - { - (1, 1669053862), (16, 2162654757), (20, 1635644926), (20, 3159649454), (20, 1649652954), (20, 3877379438), - (20, 4262788820), (20, 199934614), (8, 4235719287), (8, 1374843914), (9, 4241735292), (9, 2170796787), - (19, 1300950661), (19, 3968158929), (18, 3928463356), (18, 3928463356), (18, 2109213706), (22, 1457516325), - (22, 3939645857), (22, 1393694582), (22, 546064581), (22, 1976627334), (22, 513172946), (22, 25744891), - (22, 1989765812), (22, 2066266302), (22, 3810887196), (22, 206965504), (22, 647717352), (22, 3911072265), - (22, 3290064241), (12, 3928463356), (24, 2717331243), (24, 3687876222), (25, 2318145338), (25, 2318145338), - (6, 542071654), (15, 1810708069), (10, 3974941622), (14, 1150179208), (17, 2709606169), (13, 2361171624), - (28, 0), (28, 0), (28, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), - (23, 3467414241), (23, 4079273803), (26, 1282639619), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), - (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (5, 0), (28, 0), (28, 0), (28, 0), (27, 0), (29, 0), (29, 0), - (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (30, 0), (10, 2556510175), (21, 2556510175), - (21, 2556510175), (21, 2556510175), (21, 2556510175), (21, 2556510175), (21, 2556510175), (21, 2556510175), - (21, 2556510175), (20, 2556510175), (8, 4117779887), (31, 0), (11, 525614319), (31, 0), (31, 0), (31, 0), - (31, 0), (31, 0), (25, 2556510175), (25, 2556510175), (25, 2556510175), (25, 2556510175), (20, 3906165615), - (20, 1185345766), (20, 407658226), (22, 2869884627), (27, 0), (30, 0), (5, 0), (27, 0), (4, 0), (4, 0), - (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (5, 0), (28, 0), (28, 0), (28, 0), - (27, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (30, 0), (28, 0), (28, 0), - (28, 0), (27, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (30, 0), (4, 0), - (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (5, 0), (7, 4096381681), - (22, 454268333), (14, 1927129959), (23, 1927129959), (20, 0), (8, 0), (19, 0), (18, 0), (18, 0), (22, 0), - (24, 0), (10, 0), (14, 0), (2, 0), (31, 0), (3, 0), (3, 0) - }, dbiStream.SectionContributions.Select(x => (x.ModuleIndex, x.DataCrc))); - } - - [Fact] - public void ReadSectionMap() - { - var file = MsfFile.FromBytes(Properties.Resources.SimpleDllPdb); - var dbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader()); - - Assert.Equal(new (ushort, ushort, ushort, ushort, ushort, ushort, uint, uint)[] - { - (0x010d, 0x0000, 0x0000, 0x0001, 0xffff, 0xffff, 0x00000000, 0x00000ce8), - (0x0109, 0x0000, 0x0000, 0x0002, 0xffff, 0xffff, 0x00000000, 0x00000834), - (0x010b, 0x0000, 0x0000, 0x0003, 0xffff, 0xffff, 0x00000000, 0x00000394), - (0x0109, 0x0000, 0x0000, 0x0004, 0xffff, 0xffff, 0x00000000, 0x000000f8), - (0x0109, 0x0000, 0x0000, 0x0005, 0xffff, 0xffff, 0x00000000, 0x0000013c), - (0x0208, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0x00000000, 0xffffffff), - }, - dbiStream.SectionMaps.Select(m => ((ushort) - m.Attributes, m.LogicalOverlayNumber, m.Group, m.Frame, - m.SectionName, m.ClassName, m.Offset, m.SectionLength))); - } - - [Fact] - public void ReadSourceFiles() - { - var file = MsfFile.FromBytes(Properties.Resources.SimpleDllPdb); - var dbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader()); - - string[][] firstThreeActualFileLists = dbiStream.SourceFiles - .Take(3) - .Select(x => x - .Select(y => y.ToString()) - .ToArray() - ).ToArray(); - - Assert.Equal(new[] - { - Array.Empty(), - new[] - { - @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\pch.h", - @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\dllmain.cpp", - @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\Release\SimpleDll.pch", - }, - new[] - { - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\winuser.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\basetsd.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\winbase.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\stralign.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\guiddef.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\winerror.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\corecrt_wstring.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\processthreadsapi.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\winnt.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\ctype.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\string.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\corecrt_memory.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\memoryapi.h", - @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\corecrt_memcpy_s.h", - @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\Release\SimpleDll.pch", - } - }, - firstThreeActualFileLists); - } - - [Fact] - public void ReadExtraDebugIndices() - { - var file = MsfFile.FromBytes(Properties.Resources.SimpleDllPdb); - var dbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader()); - Assert.Equal(new ushort[] - { - 0x7, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xB, 0xFFFF, 0xFFFF, 0xFFFF, 0xD, 0xFFFF - }, dbiStream.ExtraStreamIndices); - } -} +using System; +using System.IO; +using System.Linq; +using AsmResolver.IO; +using AsmResolver.PE.File.Headers; +using AsmResolver.Symbols.Pdb.Metadata.Dbi; +using AsmResolver.Symbols.Pdb.Msf; +using Xunit; + +namespace AsmResolver.Symbols.Pdb.Tests.Metadata.Dbi; + +public class DbiStreamTest +{ + private DbiStream GetDbiStream(bool rebuild) + { + var file = MsfFile.FromBytes(Properties.Resources.SimpleDllPdb); + var dbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader()); + + File.WriteAllBytes("/tmp/dbi_original.bin", file.Streams[DbiStream.StreamIndex].CreateReader().ReadToEnd()); + + if (rebuild) + { + using var stream = new MemoryStream(); + dbiStream.Write(new BinaryStreamWriter(stream)); + + File.WriteAllBytes("/tmp/dbi_rebuild.bin", stream.ToArray()); + dbiStream = DbiStream.FromReader(ByteArrayDataSource.CreateReader(stream.ToArray())); + } + + return dbiStream; + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void Header(bool rebuild) + { + var dbiStream = GetDbiStream(rebuild); + + Assert.Equal(1u, dbiStream.Age); + Assert.Equal(DbiAttributes.None, dbiStream.Attributes); + Assert.Equal(MachineType.I386, dbiStream.Machine); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ModuleNames(bool rebuild) + { + var dbiStream = GetDbiStream(rebuild); + + Assert.Equal(new[] + { + "* CIL *", + "C:\\Users\\Admin\\source\\repos\\AsmResolver\\test\\TestBinaries\\Native\\SimpleDll\\Release\\dllmain.obj", + "C:\\Users\\Admin\\source\\repos\\AsmResolver\\test\\TestBinaries\\Native\\SimpleDll\\Release\\pch.obj", + "* Linker Generated Manifest RES *", + "Import:KERNEL32.dll", + "KERNEL32.dll", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\sehprolg4.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\gs_cookie.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\gs_report.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\gs_support.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\guard_support.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\loadcfg.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\dyn_tls_init.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\ucrt_detection.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\cpu_disp.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\chandler4gs.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\secchk.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\argv_mode.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\default_local_stdio_options.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\tncleanup.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\dll_dllmain.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\initializers.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\utility.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\ucrt_stubs.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\utility_desktop.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\initsect.obj", + "D:\\a\\_work\\1\\s\\Intermediate\\vctools\\msvcrt.nativeproj_110336922\\objr\\x86\\x86_exception_filter.obj", + "VCRUNTIME140.dll", + "Import:VCRUNTIME140.dll", + "Import:api-ms-win-crt-runtime-l1-1-0.dll", + "api-ms-win-crt-runtime-l1-1-0.dll", + "* Linker *", + }, dbiStream.Modules.Select(m => m.ModuleName?.Value)); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void SectionContributions(bool rebuild) + { + var dbiStream = GetDbiStream(rebuild); + + Assert.Equal(new (ushort, uint)[] + { + (1, 1669053862), (16, 2162654757), (20, 1635644926), (20, 3159649454), (20, 1649652954), (20, 3877379438), + (20, 4262788820), (20, 199934614), (8, 4235719287), (8, 1374843914), (9, 4241735292), (9, 2170796787), + (19, 1300950661), (19, 3968158929), (18, 3928463356), (18, 3928463356), (18, 2109213706), (22, 1457516325), + (22, 3939645857), (22, 1393694582), (22, 546064581), (22, 1976627334), (22, 513172946), (22, 25744891), + (22, 1989765812), (22, 2066266302), (22, 3810887196), (22, 206965504), (22, 647717352), (22, 3911072265), + (22, 3290064241), (12, 3928463356), (24, 2717331243), (24, 3687876222), (25, 2318145338), (25, 2318145338), + (6, 542071654), (15, 1810708069), (10, 3974941622), (14, 1150179208), (17, 2709606169), (13, 2361171624), + (28, 0), (28, 0), (28, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), + (23, 3467414241), (23, 4079273803), (26, 1282639619), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), + (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (5, 0), (28, 0), (28, 0), (28, 0), (27, 0), (29, 0), (29, 0), + (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (30, 0), (10, 2556510175), (21, 2556510175), + (21, 2556510175), (21, 2556510175), (21, 2556510175), (21, 2556510175), (21, 2556510175), (21, 2556510175), + (21, 2556510175), (20, 2556510175), (8, 4117779887), (31, 0), (11, 525614319), (31, 0), (31, 0), (31, 0), + (31, 0), (31, 0), (25, 2556510175), (25, 2556510175), (25, 2556510175), (25, 2556510175), (20, 3906165615), + (20, 1185345766), (20, 407658226), (22, 2869884627), (27, 0), (30, 0), (5, 0), (27, 0), (4, 0), (4, 0), + (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (5, 0), (28, 0), (28, 0), (28, 0), + (27, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (30, 0), (28, 0), (28, 0), + (28, 0), (27, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (29, 0), (30, 0), (4, 0), + (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (4, 0), (5, 0), (7, 4096381681), + (22, 454268333), (14, 1927129959), (23, 1927129959), (20, 0), (8, 0), (19, 0), (18, 0), (18, 0), (22, 0), + (24, 0), (10, 0), (14, 0), (2, 0), (31, 0), (3, 0), (3, 0) + }, dbiStream.SectionContributions.Select(x => (x.ModuleIndex, x.DataCrc))); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void SectionMaps(bool rebuild) + { + var dbiStream = GetDbiStream(rebuild); + + Assert.Equal(new (ushort, ushort, ushort, ushort, ushort, ushort, uint, uint)[] + { + (0x010d, 0x0000, 0x0000, 0x0001, 0xffff, 0xffff, 0x00000000, 0x00000ce8), + (0x0109, 0x0000, 0x0000, 0x0002, 0xffff, 0xffff, 0x00000000, 0x00000834), + (0x010b, 0x0000, 0x0000, 0x0003, 0xffff, 0xffff, 0x00000000, 0x00000394), + (0x0109, 0x0000, 0x0000, 0x0004, 0xffff, 0xffff, 0x00000000, 0x000000f8), + (0x0109, 0x0000, 0x0000, 0x0005, 0xffff, 0xffff, 0x00000000, 0x0000013c), + (0x0208, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0x00000000, 0xffffffff), + }, + dbiStream.SectionMaps.Select(m => ((ushort) + m.Attributes, m.LogicalOverlayNumber, m.Group, m.Frame, + m.SectionName, m.ClassName, m.Offset, m.SectionLength))); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void SourceFiles(bool rebuild) + { + var dbiStream = GetDbiStream(rebuild); + + string[][] firstThreeActualFileLists = dbiStream.SourceFiles + .Take(3) + .Select(x => x + .Select(y => y.ToString()) + .ToArray() + ).ToArray(); + + Assert.Equal(new[] + { + Array.Empty(), + new[] + { + @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\pch.h", + @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\dllmain.cpp", + @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\Release\SimpleDll.pch", + }, + new[] + { + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\winuser.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\basetsd.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\winbase.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\stralign.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\guiddef.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared\winerror.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\corecrt_wstring.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\processthreadsapi.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\winnt.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\ctype.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\string.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\corecrt_memory.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\memoryapi.h", + @"C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt\corecrt_memcpy_s.h", + @"C:\Users\Admin\source\repos\AsmResolver\test\TestBinaries\Native\SimpleDll\Release\SimpleDll.pch", + } + }, + firstThreeActualFileLists); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void ExtraDebugIndices(bool rebuild) + { + var dbiStream = GetDbiStream(rebuild); + + Assert.Equal(new ushort[] + { + 0x7, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xB, 0xFFFF, 0xFFFF, 0xFFFF, 0xD, 0xFFFF + }, dbiStream.ExtraStreamIndices); + } +}