xref: /openbsd-src/gnu/llvm/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp (revision 73471bf04ceb096474c7f0fa83b1b65c70a787a1)
109467b48Spatrick //===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick 
909467b48Spatrick #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
1009467b48Spatrick 
1109467b48Spatrick #include "llvm/ADT/ArrayRef.h"
1209467b48Spatrick #include "llvm/BinaryFormat/COFF.h"
1309467b48Spatrick #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
1409467b48Spatrick #include "llvm/DebugInfo/MSF/MSFBuilder.h"
1509467b48Spatrick #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1609467b48Spatrick #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
1709467b48Spatrick #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
1809467b48Spatrick #include "llvm/DebugInfo/PDB/Native/RawError.h"
1909467b48Spatrick #include "llvm/Object/COFF.h"
2009467b48Spatrick #include "llvm/Support/BinaryStreamWriter.h"
21*73471bf0Spatrick #include "llvm/Support/Parallel.h"
2209467b48Spatrick 
2309467b48Spatrick using namespace llvm;
2409467b48Spatrick using namespace llvm::codeview;
2509467b48Spatrick using namespace llvm::msf;
2609467b48Spatrick using namespace llvm::pdb;
2709467b48Spatrick 
2809467b48Spatrick DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
2909467b48Spatrick     : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
3009467b48Spatrick       PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
3109467b48Spatrick       Header(nullptr) {}
3209467b48Spatrick 
3309467b48Spatrick DbiStreamBuilder::~DbiStreamBuilder() {}
3409467b48Spatrick 
3509467b48Spatrick void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
3609467b48Spatrick 
3709467b48Spatrick void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
3809467b48Spatrick 
3909467b48Spatrick void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
4009467b48Spatrick 
4109467b48Spatrick void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) {
4209467b48Spatrick   BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) &
4309467b48Spatrick                 DbiBuildNo::BuildMajorMask;
4409467b48Spatrick   BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) &
4509467b48Spatrick                  DbiBuildNo::BuildMinorMask;
4609467b48Spatrick   BuildNumber |= DbiBuildNo::NewVersionFormatMask;
4709467b48Spatrick }
4809467b48Spatrick 
4909467b48Spatrick void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
5009467b48Spatrick 
5109467b48Spatrick void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
5209467b48Spatrick 
5309467b48Spatrick void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
5409467b48Spatrick 
5509467b48Spatrick void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
5609467b48Spatrick 
5709467b48Spatrick void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) {
5809467b48Spatrick   // These enums are mirrors of each other, so we can just cast the value.
5909467b48Spatrick   MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M));
6009467b48Spatrick }
6109467b48Spatrick 
6209467b48Spatrick void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) {
6309467b48Spatrick   GlobalsStreamIndex = Index;
6409467b48Spatrick }
6509467b48Spatrick 
6609467b48Spatrick void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) {
6709467b48Spatrick   SymRecordStreamIndex = Index;
6809467b48Spatrick }
6909467b48Spatrick 
7009467b48Spatrick void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) {
7109467b48Spatrick   PublicsStreamIndex = Index;
7209467b48Spatrick }
7309467b48Spatrick 
7409467b48Spatrick void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) {
7509467b48Spatrick   if (!NewFpoData.hasValue())
7609467b48Spatrick     NewFpoData.emplace(false);
7709467b48Spatrick 
7809467b48Spatrick   NewFpoData->addFrameData(FD);
7909467b48Spatrick }
8009467b48Spatrick 
8109467b48Spatrick void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) {
8209467b48Spatrick   OldFpoData.push_back(FD);
8309467b48Spatrick }
8409467b48Spatrick 
8509467b48Spatrick Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type,
8609467b48Spatrick                                      ArrayRef<uint8_t> Data) {
8709467b48Spatrick   assert(Type != DbgHeaderType::NewFPO &&
8809467b48Spatrick          "NewFPO data should be written via addFrameData()!");
8909467b48Spatrick 
9009467b48Spatrick   DbgStreams[(int)Type].emplace();
9109467b48Spatrick   DbgStreams[(int)Type]->Size = Data.size();
9209467b48Spatrick   DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) {
9309467b48Spatrick     return Writer.writeArray(Data);
9409467b48Spatrick   };
9509467b48Spatrick   return Error::success();
9609467b48Spatrick }
9709467b48Spatrick 
9809467b48Spatrick uint32_t DbiStreamBuilder::addECName(StringRef Name) {
9909467b48Spatrick   return ECNamesBuilder.insert(Name);
10009467b48Spatrick }
10109467b48Spatrick 
10209467b48Spatrick uint32_t DbiStreamBuilder::calculateSerializedLength() const {
10309467b48Spatrick   // For now we only support serializing the header.
10409467b48Spatrick   return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
10509467b48Spatrick          calculateModiSubstreamSize() + calculateSectionContribsStreamSize() +
10609467b48Spatrick          calculateSectionMapStreamSize() + calculateDbgStreamsSize() +
10709467b48Spatrick          ECNamesBuilder.calculateSerializedSize();
10809467b48Spatrick }
10909467b48Spatrick 
11009467b48Spatrick Expected<DbiModuleDescriptorBuilder &>
11109467b48Spatrick DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
11209467b48Spatrick   uint32_t Index = ModiList.size();
11309467b48Spatrick   ModiList.push_back(
11409467b48Spatrick       std::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf));
11509467b48Spatrick   return *ModiList.back();
11609467b48Spatrick }
11709467b48Spatrick 
11809467b48Spatrick Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module,
11909467b48Spatrick                                             StringRef File) {
12009467b48Spatrick   uint32_t Index = SourceFileNames.size();
12109467b48Spatrick   SourceFileNames.insert(std::make_pair(File, Index));
12209467b48Spatrick   Module.addSourceFile(File);
12309467b48Spatrick   return Error::success();
12409467b48Spatrick }
12509467b48Spatrick 
12609467b48Spatrick Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) {
12709467b48Spatrick   auto NameIter = SourceFileNames.find(File);
12809467b48Spatrick   if (NameIter == SourceFileNames.end())
12909467b48Spatrick     return make_error<RawError>(raw_error_code::no_entry,
13009467b48Spatrick                                 "The specified source file was not found");
13109467b48Spatrick   return NameIter->getValue();
13209467b48Spatrick }
13309467b48Spatrick 
13409467b48Spatrick uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
13509467b48Spatrick   uint32_t Size = 0;
13609467b48Spatrick   for (const auto &M : ModiList)
13709467b48Spatrick     Size += M->calculateSerializedLength();
13809467b48Spatrick   return Size;
13909467b48Spatrick }
14009467b48Spatrick 
14109467b48Spatrick uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const {
14209467b48Spatrick   if (SectionContribs.empty())
14309467b48Spatrick     return 0;
14409467b48Spatrick   return sizeof(enum PdbRaw_DbiSecContribVer) +
14509467b48Spatrick          sizeof(SectionContribs[0]) * SectionContribs.size();
14609467b48Spatrick }
14709467b48Spatrick 
14809467b48Spatrick uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const {
14909467b48Spatrick   if (SectionMap.empty())
15009467b48Spatrick     return 0;
15109467b48Spatrick   return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size();
15209467b48Spatrick }
15309467b48Spatrick 
15409467b48Spatrick uint32_t DbiStreamBuilder::calculateNamesOffset() const {
15509467b48Spatrick   uint32_t Offset = 0;
15609467b48Spatrick   Offset += sizeof(ulittle16_t);                         // NumModules
15709467b48Spatrick   Offset += sizeof(ulittle16_t);                         // NumSourceFiles
15809467b48Spatrick   Offset += ModiList.size() * sizeof(ulittle16_t);       // ModIndices
15909467b48Spatrick   Offset += ModiList.size() * sizeof(ulittle16_t);       // ModFileCounts
16009467b48Spatrick   uint32_t NumFileInfos = 0;
16109467b48Spatrick   for (const auto &M : ModiList)
16209467b48Spatrick     NumFileInfos += M->source_files().size();
16309467b48Spatrick   Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
16409467b48Spatrick   return Offset;
16509467b48Spatrick }
16609467b48Spatrick 
16709467b48Spatrick uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
16809467b48Spatrick   uint32_t Size = calculateNamesOffset();
16909467b48Spatrick   Size += calculateNamesBufferSize();
17009467b48Spatrick   return alignTo(Size, sizeof(uint32_t));
17109467b48Spatrick }
17209467b48Spatrick 
17309467b48Spatrick uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
17409467b48Spatrick   uint32_t Size = 0;
17509467b48Spatrick   for (const auto &F : SourceFileNames) {
17609467b48Spatrick     Size += F.getKeyLength() + 1; // Names[I];
17709467b48Spatrick   }
17809467b48Spatrick   return Size;
17909467b48Spatrick }
18009467b48Spatrick 
18109467b48Spatrick uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
18209467b48Spatrick   return DbgStreams.size() * sizeof(uint16_t);
18309467b48Spatrick }
18409467b48Spatrick 
18509467b48Spatrick Error DbiStreamBuilder::generateFileInfoSubstream() {
18609467b48Spatrick   uint32_t Size = calculateFileInfoSubstreamSize();
18709467b48Spatrick   auto Data = Allocator.Allocate<uint8_t>(Size);
18809467b48Spatrick   uint32_t NamesOffset = calculateNamesOffset();
18909467b48Spatrick 
19009467b48Spatrick   FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size),
19109467b48Spatrick                                            llvm::support::little);
19209467b48Spatrick 
19309467b48Spatrick   WritableBinaryStreamRef MetadataBuffer =
19409467b48Spatrick       WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
19509467b48Spatrick   BinaryStreamWriter MetadataWriter(MetadataBuffer);
19609467b48Spatrick 
19709467b48Spatrick   uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size());
19809467b48Spatrick   uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
19909467b48Spatrick   if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
20009467b48Spatrick     return EC;
20109467b48Spatrick   if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
20209467b48Spatrick     return EC;
20309467b48Spatrick   for (uint16_t I = 0; I < ModiCount; ++I) {
20409467b48Spatrick     if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
20509467b48Spatrick       return EC;
20609467b48Spatrick   }
20709467b48Spatrick   for (const auto &MI : ModiList) {
20809467b48Spatrick     FileCount = static_cast<uint16_t>(MI->source_files().size());
20909467b48Spatrick     if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
21009467b48Spatrick       return EC;
21109467b48Spatrick   }
21209467b48Spatrick 
21309467b48Spatrick   // Before writing the FileNameOffsets array, write the NamesBuffer array.
21409467b48Spatrick   // A side effect of this is that this will actually compute the various
21509467b48Spatrick   // file name offsets, so we can then go back and write the FileNameOffsets
21609467b48Spatrick   // array to the other substream.
21709467b48Spatrick   NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset);
21809467b48Spatrick   BinaryStreamWriter NameBufferWriter(NamesBuffer);
21909467b48Spatrick   for (auto &Name : SourceFileNames) {
22009467b48Spatrick     Name.second = NameBufferWriter.getOffset();
22109467b48Spatrick     if (auto EC = NameBufferWriter.writeCString(Name.getKey()))
22209467b48Spatrick       return EC;
22309467b48Spatrick   }
22409467b48Spatrick 
22509467b48Spatrick   for (const auto &MI : ModiList) {
22609467b48Spatrick     for (StringRef Name : MI->source_files()) {
22709467b48Spatrick       auto Result = SourceFileNames.find(Name);
22809467b48Spatrick       if (Result == SourceFileNames.end())
22909467b48Spatrick         return make_error<RawError>(raw_error_code::no_entry,
23009467b48Spatrick                                     "The source file was not found.");
23109467b48Spatrick       if (auto EC = MetadataWriter.writeInteger(Result->second))
23209467b48Spatrick         return EC;
23309467b48Spatrick     }
23409467b48Spatrick   }
23509467b48Spatrick 
23609467b48Spatrick   if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t)))
23709467b48Spatrick     return EC;
23809467b48Spatrick 
23909467b48Spatrick   if (NameBufferWriter.bytesRemaining() > 0)
24009467b48Spatrick     return make_error<RawError>(raw_error_code::invalid_format,
24109467b48Spatrick                                 "The names buffer contained unexpected data.");
24209467b48Spatrick 
24309467b48Spatrick   if (MetadataWriter.bytesRemaining() > sizeof(uint32_t))
24409467b48Spatrick     return make_error<RawError>(
24509467b48Spatrick         raw_error_code::invalid_format,
24609467b48Spatrick         "The metadata buffer contained unexpected data.");
24709467b48Spatrick 
24809467b48Spatrick   return Error::success();
24909467b48Spatrick }
25009467b48Spatrick 
25109467b48Spatrick Error DbiStreamBuilder::finalize() {
25209467b48Spatrick   if (Header)
25309467b48Spatrick     return Error::success();
25409467b48Spatrick 
25509467b48Spatrick   for (auto &MI : ModiList)
25609467b48Spatrick     MI->finalize();
25709467b48Spatrick 
25809467b48Spatrick   if (auto EC = generateFileInfoSubstream())
25909467b48Spatrick     return EC;
26009467b48Spatrick 
26109467b48Spatrick   DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
26209467b48Spatrick   ::memset(H, 0, sizeof(DbiStreamHeader));
26309467b48Spatrick   H->VersionHeader = *VerHeader;
26409467b48Spatrick   H->VersionSignature = -1;
26509467b48Spatrick   H->Age = Age;
26609467b48Spatrick   H->BuildNumber = BuildNumber;
26709467b48Spatrick   H->Flags = Flags;
26809467b48Spatrick   H->PdbDllRbld = PdbDllRbld;
26909467b48Spatrick   H->PdbDllVersion = PdbDllVersion;
27009467b48Spatrick   H->MachineType = static_cast<uint16_t>(MachineType);
27109467b48Spatrick 
27209467b48Spatrick   H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize();
27309467b48Spatrick   H->FileInfoSize = FileInfoBuffer.getLength();
27409467b48Spatrick   H->ModiSubstreamSize = calculateModiSubstreamSize();
27509467b48Spatrick   H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
27609467b48Spatrick   H->SecContrSubstreamSize = calculateSectionContribsStreamSize();
27709467b48Spatrick   H->SectionMapSize = calculateSectionMapStreamSize();
27809467b48Spatrick   H->TypeServerSize = 0;
27909467b48Spatrick   H->SymRecordStreamIndex = SymRecordStreamIndex;
28009467b48Spatrick   H->PublicSymbolStreamIndex = PublicsStreamIndex;
28109467b48Spatrick   H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0.
28209467b48Spatrick   H->GlobalSymbolStreamIndex = GlobalsStreamIndex;
28309467b48Spatrick 
28409467b48Spatrick   Header = H;
28509467b48Spatrick   return Error::success();
28609467b48Spatrick }
28709467b48Spatrick 
28809467b48Spatrick Error DbiStreamBuilder::finalizeMsfLayout() {
28909467b48Spatrick   if (NewFpoData.hasValue()) {
29009467b48Spatrick     DbgStreams[(int)DbgHeaderType::NewFPO].emplace();
29109467b48Spatrick     DbgStreams[(int)DbgHeaderType::NewFPO]->Size =
29209467b48Spatrick         NewFpoData->calculateSerializedSize();
29309467b48Spatrick     DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn =
29409467b48Spatrick         [this](BinaryStreamWriter &Writer) {
29509467b48Spatrick           return NewFpoData->commit(Writer);
29609467b48Spatrick         };
29709467b48Spatrick   }
29809467b48Spatrick 
29909467b48Spatrick   if (!OldFpoData.empty()) {
30009467b48Spatrick     DbgStreams[(int)DbgHeaderType::FPO].emplace();
30109467b48Spatrick     DbgStreams[(int)DbgHeaderType::FPO]->Size =
30209467b48Spatrick         sizeof(object::FpoData) * OldFpoData.size();
30309467b48Spatrick     DbgStreams[(int)DbgHeaderType::FPO]->WriteFn =
30409467b48Spatrick         [this](BinaryStreamWriter &Writer) {
30509467b48Spatrick           return Writer.writeArray(makeArrayRef(OldFpoData));
30609467b48Spatrick         };
30709467b48Spatrick   }
30809467b48Spatrick 
30909467b48Spatrick   for (auto &S : DbgStreams) {
31009467b48Spatrick     if (!S.hasValue())
31109467b48Spatrick       continue;
31209467b48Spatrick     auto ExpectedIndex = Msf.addStream(S->Size);
31309467b48Spatrick     if (!ExpectedIndex)
31409467b48Spatrick       return ExpectedIndex.takeError();
31509467b48Spatrick     S->StreamNumber = *ExpectedIndex;
31609467b48Spatrick   }
31709467b48Spatrick 
31809467b48Spatrick   for (auto &MI : ModiList) {
31909467b48Spatrick     if (auto EC = MI->finalizeMsfLayout())
32009467b48Spatrick       return EC;
32109467b48Spatrick   }
32209467b48Spatrick 
32309467b48Spatrick   uint32_t Length = calculateSerializedLength();
32409467b48Spatrick   if (auto EC = Msf.setStreamSize(StreamDBI, Length))
32509467b48Spatrick     return EC;
32609467b48Spatrick   return Error::success();
32709467b48Spatrick }
32809467b48Spatrick 
32909467b48Spatrick static uint16_t toSecMapFlags(uint32_t Flags) {
33009467b48Spatrick   uint16_t Ret = 0;
33109467b48Spatrick   if (Flags & COFF::IMAGE_SCN_MEM_READ)
33209467b48Spatrick     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read);
33309467b48Spatrick   if (Flags & COFF::IMAGE_SCN_MEM_WRITE)
33409467b48Spatrick     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write);
33509467b48Spatrick   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
33609467b48Spatrick     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
33709467b48Spatrick   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
33809467b48Spatrick     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
33909467b48Spatrick   if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT))
34009467b48Spatrick     Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit);
34109467b48Spatrick 
34209467b48Spatrick   // This seems always 1.
34309467b48Spatrick   Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector);
34409467b48Spatrick 
34509467b48Spatrick   return Ret;
34609467b48Spatrick }
34709467b48Spatrick 
348097a140dSpatrick // Populate the Section Map from COFF section headers.
34909467b48Spatrick //
35009467b48Spatrick // A Section Map seem to be a copy of a COFF section list in other format.
35109467b48Spatrick // I don't know why a PDB file contains both a COFF section header and
35209467b48Spatrick // a Section Map, but it seems it must be present in a PDB.
353097a140dSpatrick void DbiStreamBuilder::createSectionMap(
35409467b48Spatrick     ArrayRef<llvm::object::coff_section> SecHdrs) {
35509467b48Spatrick   int Idx = 0;
35609467b48Spatrick 
35709467b48Spatrick   auto Add = [&]() -> SecMapEntry & {
358097a140dSpatrick     SectionMap.emplace_back();
359097a140dSpatrick     auto &Entry = SectionMap.back();
36009467b48Spatrick     memset(&Entry, 0, sizeof(Entry));
36109467b48Spatrick 
36209467b48Spatrick     Entry.Frame = Idx + 1;
36309467b48Spatrick 
36409467b48Spatrick     // We don't know the meaning of these fields yet.
36509467b48Spatrick     Entry.SecName = UINT16_MAX;
36609467b48Spatrick     Entry.ClassName = UINT16_MAX;
36709467b48Spatrick 
36809467b48Spatrick     return Entry;
36909467b48Spatrick   };
37009467b48Spatrick 
37109467b48Spatrick   for (auto &Hdr : SecHdrs) {
37209467b48Spatrick     auto &Entry = Add();
37309467b48Spatrick     Entry.Flags = toSecMapFlags(Hdr.Characteristics);
37409467b48Spatrick     Entry.SecByteLength = Hdr.VirtualSize;
37509467b48Spatrick     ++Idx;
37609467b48Spatrick   }
37709467b48Spatrick 
37809467b48Spatrick   // The last entry is for absolute symbols.
37909467b48Spatrick   auto &Entry = Add();
38009467b48Spatrick   Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) |
38109467b48Spatrick                 static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress);
38209467b48Spatrick   Entry.SecByteLength = UINT32_MAX;
38309467b48Spatrick }
38409467b48Spatrick 
38509467b48Spatrick Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
38609467b48Spatrick                                WritableBinaryStreamRef MsfBuffer) {
38709467b48Spatrick   if (auto EC = finalize())
38809467b48Spatrick     return EC;
38909467b48Spatrick 
39009467b48Spatrick   auto DbiS = WritableMappedBlockStream::createIndexedStream(
39109467b48Spatrick       Layout, MsfBuffer, StreamDBI, Allocator);
39209467b48Spatrick 
39309467b48Spatrick   BinaryStreamWriter Writer(*DbiS);
39409467b48Spatrick   if (auto EC = Writer.writeObject(*Header))
39509467b48Spatrick     return EC;
39609467b48Spatrick 
39709467b48Spatrick   for (auto &M : ModiList) {
398*73471bf0Spatrick     if (auto EC = M->commit(Writer))
39909467b48Spatrick       return EC;
40009467b48Spatrick   }
40109467b48Spatrick 
402*73471bf0Spatrick   // Commit symbol streams. This is a lot of data, so do it in parallel.
403*73471bf0Spatrick   if (auto EC = parallelForEachError(
404*73471bf0Spatrick           ModiList, [&](std::unique_ptr<DbiModuleDescriptorBuilder> &M) {
405*73471bf0Spatrick             return M->commitSymbolStream(Layout, MsfBuffer);
406*73471bf0Spatrick           }))
407*73471bf0Spatrick     return EC;
408*73471bf0Spatrick 
40909467b48Spatrick   if (!SectionContribs.empty()) {
41009467b48Spatrick     if (auto EC = Writer.writeEnum(DbiSecContribVer60))
41109467b48Spatrick       return EC;
41209467b48Spatrick     if (auto EC = Writer.writeArray(makeArrayRef(SectionContribs)))
41309467b48Spatrick       return EC;
41409467b48Spatrick   }
41509467b48Spatrick 
41609467b48Spatrick   if (!SectionMap.empty()) {
41709467b48Spatrick     ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size());
41809467b48Spatrick     SecMapHeader SMHeader = {Size, Size};
41909467b48Spatrick     if (auto EC = Writer.writeObject(SMHeader))
42009467b48Spatrick       return EC;
421097a140dSpatrick     if (auto EC = Writer.writeArray(makeArrayRef(SectionMap)))
42209467b48Spatrick       return EC;
42309467b48Spatrick   }
42409467b48Spatrick 
42509467b48Spatrick   if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
42609467b48Spatrick     return EC;
42709467b48Spatrick 
42809467b48Spatrick   if (auto EC = ECNamesBuilder.commit(Writer))
42909467b48Spatrick     return EC;
43009467b48Spatrick 
43109467b48Spatrick   for (auto &Stream : DbgStreams) {
43209467b48Spatrick     uint16_t StreamNumber = kInvalidStreamIndex;
43309467b48Spatrick     if (Stream.hasValue())
43409467b48Spatrick       StreamNumber = Stream->StreamNumber;
43509467b48Spatrick     if (auto EC = Writer.writeInteger(StreamNumber))
43609467b48Spatrick       return EC;
43709467b48Spatrick   }
43809467b48Spatrick 
43909467b48Spatrick   for (auto &Stream : DbgStreams) {
44009467b48Spatrick     if (!Stream.hasValue())
44109467b48Spatrick       continue;
44209467b48Spatrick     assert(Stream->StreamNumber != kInvalidStreamIndex);
44309467b48Spatrick 
44409467b48Spatrick     auto WritableStream = WritableMappedBlockStream::createIndexedStream(
44509467b48Spatrick         Layout, MsfBuffer, Stream->StreamNumber, Allocator);
44609467b48Spatrick     BinaryStreamWriter DbgStreamWriter(*WritableStream);
44709467b48Spatrick 
44809467b48Spatrick     if (auto EC = Stream->WriteFn(DbgStreamWriter))
44909467b48Spatrick       return EC;
45009467b48Spatrick   }
45109467b48Spatrick 
45209467b48Spatrick   if (Writer.bytesRemaining() > 0)
45309467b48Spatrick     return make_error<RawError>(raw_error_code::invalid_format,
45409467b48Spatrick                                 "Unexpected bytes found in DBI Stream");
45509467b48Spatrick   return Error::success();
45609467b48Spatrick }
457