10b57cec5SDimitry Andric //===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
120b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
130b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
140b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MSFBuilder.h"
150b57cec5SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawError.h"
180b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
190b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamWriter.h"
20e8d8bef9SDimitry Andric #include "llvm/Support/Parallel.h"
215f757f3fSDimitry Andric #include "llvm/Support/TimeProfiler.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric using namespace llvm::codeview;
250b57cec5SDimitry Andric using namespace llvm::msf;
260b57cec5SDimitry Andric using namespace llvm::pdb;
270b57cec5SDimitry Andric 
DbiStreamBuilder(msf::MSFBuilder & Msf)280b57cec5SDimitry Andric DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
290b57cec5SDimitry Andric     : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
300b57cec5SDimitry Andric       PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
310b57cec5SDimitry Andric       Header(nullptr) {}
320b57cec5SDimitry Andric 
3381ad6265SDimitry Andric DbiStreamBuilder::~DbiStreamBuilder() = default;
340b57cec5SDimitry Andric 
setVersionHeader(PdbRaw_DbiVer V)350b57cec5SDimitry Andric void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
360b57cec5SDimitry Andric 
setAge(uint32_t A)370b57cec5SDimitry Andric void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
380b57cec5SDimitry Andric 
setBuildNumber(uint16_t B)390b57cec5SDimitry Andric void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
400b57cec5SDimitry Andric 
setBuildNumber(uint8_t Major,uint8_t Minor)410b57cec5SDimitry Andric void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) {
420b57cec5SDimitry Andric   BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) &
430b57cec5SDimitry Andric                 DbiBuildNo::BuildMajorMask;
440b57cec5SDimitry Andric   BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) &
450b57cec5SDimitry Andric                  DbiBuildNo::BuildMinorMask;
460b57cec5SDimitry Andric   BuildNumber |= DbiBuildNo::NewVersionFormatMask;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
setPdbDllVersion(uint16_t V)490b57cec5SDimitry Andric void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
500b57cec5SDimitry Andric 
setPdbDllRbld(uint16_t R)510b57cec5SDimitry Andric void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
520b57cec5SDimitry Andric 
setFlags(uint16_t F)530b57cec5SDimitry Andric void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
540b57cec5SDimitry Andric 
setMachineType(PDB_Machine M)550b57cec5SDimitry Andric void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
560b57cec5SDimitry Andric 
setMachineType(COFF::MachineTypes M)570b57cec5SDimitry Andric void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) {
580b57cec5SDimitry Andric   // These enums are mirrors of each other, so we can just cast the value.
590b57cec5SDimitry Andric   MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M));
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
setGlobalsStreamIndex(uint32_t Index)620b57cec5SDimitry Andric void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) {
630b57cec5SDimitry Andric   GlobalsStreamIndex = Index;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
setSymbolRecordStreamIndex(uint32_t Index)660b57cec5SDimitry Andric void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) {
670b57cec5SDimitry Andric   SymRecordStreamIndex = Index;
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
setPublicsStreamIndex(uint32_t Index)700b57cec5SDimitry Andric void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) {
710b57cec5SDimitry Andric   PublicsStreamIndex = Index;
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
addNewFpoData(const codeview::FrameData & FD)740b57cec5SDimitry Andric void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) {
7581ad6265SDimitry Andric   if (!NewFpoData)
760b57cec5SDimitry Andric     NewFpoData.emplace(false);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric   NewFpoData->addFrameData(FD);
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
addOldFpoData(const object::FpoData & FD)810b57cec5SDimitry Andric void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) {
820b57cec5SDimitry Andric   OldFpoData.push_back(FD);
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
addDbgStream(pdb::DbgHeaderType Type,ArrayRef<uint8_t> Data)850b57cec5SDimitry Andric Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type,
860b57cec5SDimitry Andric                                      ArrayRef<uint8_t> Data) {
870b57cec5SDimitry Andric   assert(Type != DbgHeaderType::NewFPO &&
880b57cec5SDimitry Andric          "NewFPO data should be written via addFrameData()!");
890b57cec5SDimitry Andric 
90bdd1243dSDimitry Andric   DbgStreams[(int)Type] = DebugStream{};
910b57cec5SDimitry Andric   DbgStreams[(int)Type]->Size = Data.size();
920b57cec5SDimitry Andric   DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) {
930b57cec5SDimitry Andric     return Writer.writeArray(Data);
940b57cec5SDimitry Andric   };
950b57cec5SDimitry Andric   return Error::success();
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
addECName(StringRef Name)980b57cec5SDimitry Andric uint32_t DbiStreamBuilder::addECName(StringRef Name) {
990b57cec5SDimitry Andric   return ECNamesBuilder.insert(Name);
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
calculateSerializedLength() const1020b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateSerializedLength() const {
1030b57cec5SDimitry Andric   // For now we only support serializing the header.
1040b57cec5SDimitry Andric   return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
1050b57cec5SDimitry Andric          calculateModiSubstreamSize() + calculateSectionContribsStreamSize() +
1060b57cec5SDimitry Andric          calculateSectionMapStreamSize() + calculateDbgStreamsSize() +
1070b57cec5SDimitry Andric          ECNamesBuilder.calculateSerializedSize();
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric Expected<DbiModuleDescriptorBuilder &>
addModuleInfo(StringRef ModuleName)1110b57cec5SDimitry Andric DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
1120b57cec5SDimitry Andric   uint32_t Index = ModiList.size();
1130b57cec5SDimitry Andric   ModiList.push_back(
1148bcb0991SDimitry Andric       std::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf));
1150b57cec5SDimitry Andric   return *ModiList.back();
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
addModuleSourceFile(DbiModuleDescriptorBuilder & Module,StringRef File)1180b57cec5SDimitry Andric Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module,
1190b57cec5SDimitry Andric                                             StringRef File) {
1200b57cec5SDimitry Andric   uint32_t Index = SourceFileNames.size();
1210b57cec5SDimitry Andric   SourceFileNames.insert(std::make_pair(File, Index));
1220b57cec5SDimitry Andric   Module.addSourceFile(File);
1230b57cec5SDimitry Andric   return Error::success();
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric 
getSourceFileNameIndex(StringRef File)1260b57cec5SDimitry Andric Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) {
1270b57cec5SDimitry Andric   auto NameIter = SourceFileNames.find(File);
1280b57cec5SDimitry Andric   if (NameIter == SourceFileNames.end())
1290b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::no_entry,
1300b57cec5SDimitry Andric                                 "The specified source file was not found");
1310b57cec5SDimitry Andric   return NameIter->getValue();
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
calculateModiSubstreamSize() const1340b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
1350b57cec5SDimitry Andric   uint32_t Size = 0;
1360b57cec5SDimitry Andric   for (const auto &M : ModiList)
1370b57cec5SDimitry Andric     Size += M->calculateSerializedLength();
1380b57cec5SDimitry Andric   return Size;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
calculateSectionContribsStreamSize() const1410b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const {
1420b57cec5SDimitry Andric   if (SectionContribs.empty())
1430b57cec5SDimitry Andric     return 0;
1440b57cec5SDimitry Andric   return sizeof(enum PdbRaw_DbiSecContribVer) +
1450b57cec5SDimitry Andric          sizeof(SectionContribs[0]) * SectionContribs.size();
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
calculateSectionMapStreamSize() const1480b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const {
1490b57cec5SDimitry Andric   if (SectionMap.empty())
1500b57cec5SDimitry Andric     return 0;
1510b57cec5SDimitry Andric   return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size();
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
calculateNamesOffset() const1540b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateNamesOffset() const {
1550b57cec5SDimitry Andric   uint32_t Offset = 0;
1560b57cec5SDimitry Andric   Offset += sizeof(ulittle16_t);                         // NumModules
1570b57cec5SDimitry Andric   Offset += sizeof(ulittle16_t);                         // NumSourceFiles
1580b57cec5SDimitry Andric   Offset += ModiList.size() * sizeof(ulittle16_t);       // ModIndices
1590b57cec5SDimitry Andric   Offset += ModiList.size() * sizeof(ulittle16_t);       // ModFileCounts
1600b57cec5SDimitry Andric   uint32_t NumFileInfos = 0;
1610b57cec5SDimitry Andric   for (const auto &M : ModiList)
1620b57cec5SDimitry Andric     NumFileInfos += M->source_files().size();
1630b57cec5SDimitry Andric   Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
1640b57cec5SDimitry Andric   return Offset;
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
calculateFileInfoSubstreamSize() const1670b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
1680b57cec5SDimitry Andric   uint32_t Size = calculateNamesOffset();
1690b57cec5SDimitry Andric   Size += calculateNamesBufferSize();
1700b57cec5SDimitry Andric   return alignTo(Size, sizeof(uint32_t));
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric 
calculateNamesBufferSize() const1730b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
1740b57cec5SDimitry Andric   uint32_t Size = 0;
1750b57cec5SDimitry Andric   for (const auto &F : SourceFileNames) {
1760b57cec5SDimitry Andric     Size += F.getKeyLength() + 1; // Names[I];
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric   return Size;
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
calculateDbgStreamsSize() const1810b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
1820b57cec5SDimitry Andric   return DbgStreams.size() * sizeof(uint16_t);
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
generateFileInfoSubstream()1850b57cec5SDimitry Andric Error DbiStreamBuilder::generateFileInfoSubstream() {
1860b57cec5SDimitry Andric   uint32_t Size = calculateFileInfoSubstreamSize();
1870b57cec5SDimitry Andric   auto Data = Allocator.Allocate<uint8_t>(Size);
1880b57cec5SDimitry Andric   uint32_t NamesOffset = calculateNamesOffset();
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric   FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size),
1915f757f3fSDimitry Andric                                            llvm::endianness::little);
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   WritableBinaryStreamRef MetadataBuffer =
1940b57cec5SDimitry Andric       WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
1950b57cec5SDimitry Andric   BinaryStreamWriter MetadataWriter(MetadataBuffer);
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size());
1980b57cec5SDimitry Andric   uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
1990b57cec5SDimitry Andric   if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
2000b57cec5SDimitry Andric     return EC;
2010b57cec5SDimitry Andric   if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
2020b57cec5SDimitry Andric     return EC;
2030b57cec5SDimitry Andric   for (uint16_t I = 0; I < ModiCount; ++I) {
2040b57cec5SDimitry Andric     if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
2050b57cec5SDimitry Andric       return EC;
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric   for (const auto &MI : ModiList) {
2080b57cec5SDimitry Andric     FileCount = static_cast<uint16_t>(MI->source_files().size());
2090b57cec5SDimitry Andric     if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
2100b57cec5SDimitry Andric       return EC;
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   // Before writing the FileNameOffsets array, write the NamesBuffer array.
2140b57cec5SDimitry Andric   // A side effect of this is that this will actually compute the various
2150b57cec5SDimitry Andric   // file name offsets, so we can then go back and write the FileNameOffsets
2160b57cec5SDimitry Andric   // array to the other substream.
2170b57cec5SDimitry Andric   NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset);
2180b57cec5SDimitry Andric   BinaryStreamWriter NameBufferWriter(NamesBuffer);
2190b57cec5SDimitry Andric   for (auto &Name : SourceFileNames) {
2200b57cec5SDimitry Andric     Name.second = NameBufferWriter.getOffset();
2210b57cec5SDimitry Andric     if (auto EC = NameBufferWriter.writeCString(Name.getKey()))
2220b57cec5SDimitry Andric       return EC;
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric   for (const auto &MI : ModiList) {
2260b57cec5SDimitry Andric     for (StringRef Name : MI->source_files()) {
2270b57cec5SDimitry Andric       auto Result = SourceFileNames.find(Name);
2280b57cec5SDimitry Andric       if (Result == SourceFileNames.end())
2290b57cec5SDimitry Andric         return make_error<RawError>(raw_error_code::no_entry,
2300b57cec5SDimitry Andric                                     "The source file was not found.");
2310b57cec5SDimitry Andric       if (auto EC = MetadataWriter.writeInteger(Result->second))
2320b57cec5SDimitry Andric         return EC;
2330b57cec5SDimitry Andric     }
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t)))
2370b57cec5SDimitry Andric     return EC;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   if (NameBufferWriter.bytesRemaining() > 0)
2400b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::invalid_format,
2410b57cec5SDimitry Andric                                 "The names buffer contained unexpected data.");
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric   if (MetadataWriter.bytesRemaining() > sizeof(uint32_t))
2440b57cec5SDimitry Andric     return make_error<RawError>(
2450b57cec5SDimitry Andric         raw_error_code::invalid_format,
2460b57cec5SDimitry Andric         "The metadata buffer contained unexpected data.");
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   return Error::success();
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
finalize()2510b57cec5SDimitry Andric Error DbiStreamBuilder::finalize() {
2520b57cec5SDimitry Andric   if (Header)
2530b57cec5SDimitry Andric     return Error::success();
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   for (auto &MI : ModiList)
2560b57cec5SDimitry Andric     MI->finalize();
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   if (auto EC = generateFileInfoSubstream())
2590b57cec5SDimitry Andric     return EC;
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
2620b57cec5SDimitry Andric   ::memset(H, 0, sizeof(DbiStreamHeader));
2630b57cec5SDimitry Andric   H->VersionHeader = *VerHeader;
2640b57cec5SDimitry Andric   H->VersionSignature = -1;
2650b57cec5SDimitry Andric   H->Age = Age;
2660b57cec5SDimitry Andric   H->BuildNumber = BuildNumber;
2670b57cec5SDimitry Andric   H->Flags = Flags;
2680b57cec5SDimitry Andric   H->PdbDllRbld = PdbDllRbld;
2690b57cec5SDimitry Andric   H->PdbDllVersion = PdbDllVersion;
2700b57cec5SDimitry Andric   H->MachineType = static_cast<uint16_t>(MachineType);
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric   H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize();
2730b57cec5SDimitry Andric   H->FileInfoSize = FileInfoBuffer.getLength();
2740b57cec5SDimitry Andric   H->ModiSubstreamSize = calculateModiSubstreamSize();
2750b57cec5SDimitry Andric   H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
2760b57cec5SDimitry Andric   H->SecContrSubstreamSize = calculateSectionContribsStreamSize();
2770b57cec5SDimitry Andric   H->SectionMapSize = calculateSectionMapStreamSize();
2780b57cec5SDimitry Andric   H->TypeServerSize = 0;
2790b57cec5SDimitry Andric   H->SymRecordStreamIndex = SymRecordStreamIndex;
2800b57cec5SDimitry Andric   H->PublicSymbolStreamIndex = PublicsStreamIndex;
2810b57cec5SDimitry Andric   H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0.
2820b57cec5SDimitry Andric   H->GlobalSymbolStreamIndex = GlobalsStreamIndex;
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   Header = H;
2850b57cec5SDimitry Andric   return Error::success();
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
finalizeMsfLayout()2880b57cec5SDimitry Andric Error DbiStreamBuilder::finalizeMsfLayout() {
28981ad6265SDimitry Andric   if (NewFpoData) {
290bdd1243dSDimitry Andric     DbgStreams[(int)DbgHeaderType::NewFPO] = DebugStream{};
2910b57cec5SDimitry Andric     DbgStreams[(int)DbgHeaderType::NewFPO]->Size =
2920b57cec5SDimitry Andric         NewFpoData->calculateSerializedSize();
2930b57cec5SDimitry Andric     DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn =
2940b57cec5SDimitry Andric         [this](BinaryStreamWriter &Writer) {
2950b57cec5SDimitry Andric           return NewFpoData->commit(Writer);
2960b57cec5SDimitry Andric         };
2970b57cec5SDimitry Andric   }
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric   if (!OldFpoData.empty()) {
300bdd1243dSDimitry Andric     DbgStreams[(int)DbgHeaderType::FPO] = DebugStream{};
3010b57cec5SDimitry Andric     DbgStreams[(int)DbgHeaderType::FPO]->Size =
3020b57cec5SDimitry Andric         sizeof(object::FpoData) * OldFpoData.size();
3030b57cec5SDimitry Andric     DbgStreams[(int)DbgHeaderType::FPO]->WriteFn =
3040b57cec5SDimitry Andric         [this](BinaryStreamWriter &Writer) {
305bdd1243dSDimitry Andric           return Writer.writeArray(ArrayRef(OldFpoData));
3060b57cec5SDimitry Andric         };
3070b57cec5SDimitry Andric   }
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   for (auto &S : DbgStreams) {
31081ad6265SDimitry Andric     if (!S)
3110b57cec5SDimitry Andric       continue;
3120b57cec5SDimitry Andric     auto ExpectedIndex = Msf.addStream(S->Size);
3130b57cec5SDimitry Andric     if (!ExpectedIndex)
3140b57cec5SDimitry Andric       return ExpectedIndex.takeError();
3150b57cec5SDimitry Andric     S->StreamNumber = *ExpectedIndex;
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   for (auto &MI : ModiList) {
3190b57cec5SDimitry Andric     if (auto EC = MI->finalizeMsfLayout())
3200b57cec5SDimitry Andric       return EC;
3210b57cec5SDimitry Andric   }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   uint32_t Length = calculateSerializedLength();
3240b57cec5SDimitry Andric   if (auto EC = Msf.setStreamSize(StreamDBI, Length))
3250b57cec5SDimitry Andric     return EC;
3260b57cec5SDimitry Andric   return Error::success();
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric 
toSecMapFlags(uint32_t Flags)3290b57cec5SDimitry Andric static uint16_t toSecMapFlags(uint32_t Flags) {
3300b57cec5SDimitry Andric   uint16_t Ret = 0;
3310b57cec5SDimitry Andric   if (Flags & COFF::IMAGE_SCN_MEM_READ)
3320b57cec5SDimitry Andric     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read);
3330b57cec5SDimitry Andric   if (Flags & COFF::IMAGE_SCN_MEM_WRITE)
3340b57cec5SDimitry Andric     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write);
3350b57cec5SDimitry Andric   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
3360b57cec5SDimitry Andric     Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
3370b57cec5SDimitry Andric   if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT))
3380b57cec5SDimitry Andric     Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit);
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric   // This seems always 1.
3410b57cec5SDimitry Andric   Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector);
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   return Ret;
3440b57cec5SDimitry Andric }
3450b57cec5SDimitry Andric 
3465ffd83dbSDimitry Andric // Populate the Section Map from COFF section headers.
3470b57cec5SDimitry Andric //
3480b57cec5SDimitry Andric // A Section Map seem to be a copy of a COFF section list in other format.
3490b57cec5SDimitry Andric // I don't know why a PDB file contains both a COFF section header and
3500b57cec5SDimitry Andric // a Section Map, but it seems it must be present in a PDB.
createSectionMap(ArrayRef<llvm::object::coff_section> SecHdrs)3515ffd83dbSDimitry Andric void DbiStreamBuilder::createSectionMap(
3520b57cec5SDimitry Andric     ArrayRef<llvm::object::coff_section> SecHdrs) {
3530b57cec5SDimitry Andric   int Idx = 0;
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   auto Add = [&]() -> SecMapEntry & {
3565ffd83dbSDimitry Andric     SectionMap.emplace_back();
3575ffd83dbSDimitry Andric     auto &Entry = SectionMap.back();
3580b57cec5SDimitry Andric     memset(&Entry, 0, sizeof(Entry));
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric     Entry.Frame = Idx + 1;
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric     // We don't know the meaning of these fields yet.
3630b57cec5SDimitry Andric     Entry.SecName = UINT16_MAX;
3640b57cec5SDimitry Andric     Entry.ClassName = UINT16_MAX;
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric     return Entry;
3670b57cec5SDimitry Andric   };
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   for (auto &Hdr : SecHdrs) {
3700b57cec5SDimitry Andric     auto &Entry = Add();
3710b57cec5SDimitry Andric     Entry.Flags = toSecMapFlags(Hdr.Characteristics);
3720b57cec5SDimitry Andric     Entry.SecByteLength = Hdr.VirtualSize;
3730b57cec5SDimitry Andric     ++Idx;
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   // The last entry is for absolute symbols.
3770b57cec5SDimitry Andric   auto &Entry = Add();
3780b57cec5SDimitry Andric   Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) |
3790b57cec5SDimitry Andric                 static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress);
3800b57cec5SDimitry Andric   Entry.SecByteLength = UINT32_MAX;
3810b57cec5SDimitry Andric }
3820b57cec5SDimitry Andric 
commit(const msf::MSFLayout & Layout,WritableBinaryStreamRef MsfBuffer)3830b57cec5SDimitry Andric Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
3840b57cec5SDimitry Andric                                WritableBinaryStreamRef MsfBuffer) {
3855f757f3fSDimitry Andric   llvm::TimeTraceScope timeScope("Commit DBI stream");
3860b57cec5SDimitry Andric   if (auto EC = finalize())
3870b57cec5SDimitry Andric     return EC;
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   auto DbiS = WritableMappedBlockStream::createIndexedStream(
3900b57cec5SDimitry Andric       Layout, MsfBuffer, StreamDBI, Allocator);
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   BinaryStreamWriter Writer(*DbiS);
3930b57cec5SDimitry Andric   if (auto EC = Writer.writeObject(*Header))
3940b57cec5SDimitry Andric     return EC;
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   for (auto &M : ModiList) {
397e8d8bef9SDimitry Andric     if (auto EC = M->commit(Writer))
3980b57cec5SDimitry Andric       return EC;
3990b57cec5SDimitry Andric   }
4000b57cec5SDimitry Andric 
401e8d8bef9SDimitry Andric   // Commit symbol streams. This is a lot of data, so do it in parallel.
402e8d8bef9SDimitry Andric   if (auto EC = parallelForEachError(
403e8d8bef9SDimitry Andric           ModiList, [&](std::unique_ptr<DbiModuleDescriptorBuilder> &M) {
404e8d8bef9SDimitry Andric             return M->commitSymbolStream(Layout, MsfBuffer);
405e8d8bef9SDimitry Andric           }))
406e8d8bef9SDimitry Andric     return EC;
407e8d8bef9SDimitry Andric 
4080b57cec5SDimitry Andric   if (!SectionContribs.empty()) {
4090b57cec5SDimitry Andric     if (auto EC = Writer.writeEnum(DbiSecContribVer60))
4100b57cec5SDimitry Andric       return EC;
411bdd1243dSDimitry Andric     if (auto EC = Writer.writeArray(ArrayRef(SectionContribs)))
4120b57cec5SDimitry Andric       return EC;
4130b57cec5SDimitry Andric   }
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   if (!SectionMap.empty()) {
4160b57cec5SDimitry Andric     ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size());
4170b57cec5SDimitry Andric     SecMapHeader SMHeader = {Size, Size};
4180b57cec5SDimitry Andric     if (auto EC = Writer.writeObject(SMHeader))
4190b57cec5SDimitry Andric       return EC;
420bdd1243dSDimitry Andric     if (auto EC = Writer.writeArray(ArrayRef(SectionMap)))
4210b57cec5SDimitry Andric       return EC;
4220b57cec5SDimitry Andric   }
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric   if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
4250b57cec5SDimitry Andric     return EC;
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric   if (auto EC = ECNamesBuilder.commit(Writer))
4280b57cec5SDimitry Andric     return EC;
4290b57cec5SDimitry Andric 
4300b57cec5SDimitry Andric   for (auto &Stream : DbgStreams) {
4310b57cec5SDimitry Andric     uint16_t StreamNumber = kInvalidStreamIndex;
43281ad6265SDimitry Andric     if (Stream)
4330b57cec5SDimitry Andric       StreamNumber = Stream->StreamNumber;
4340b57cec5SDimitry Andric     if (auto EC = Writer.writeInteger(StreamNumber))
4350b57cec5SDimitry Andric       return EC;
4360b57cec5SDimitry Andric   }
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric   for (auto &Stream : DbgStreams) {
43981ad6265SDimitry Andric     if (!Stream)
4400b57cec5SDimitry Andric       continue;
4410b57cec5SDimitry Andric     assert(Stream->StreamNumber != kInvalidStreamIndex);
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric     auto WritableStream = WritableMappedBlockStream::createIndexedStream(
4440b57cec5SDimitry Andric         Layout, MsfBuffer, Stream->StreamNumber, Allocator);
4450b57cec5SDimitry Andric     BinaryStreamWriter DbgStreamWriter(*WritableStream);
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric     if (auto EC = Stream->WriteFn(DbgStreamWriter))
4480b57cec5SDimitry Andric       return EC;
4490b57cec5SDimitry Andric   }
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric   if (Writer.bytesRemaining() > 0)
4520b57cec5SDimitry Andric     return make_error<RawError>(raw_error_code::invalid_format,
4530b57cec5SDimitry Andric                                 "Unexpected bytes found in DBI Stream");
4540b57cec5SDimitry Andric   return Error::success();
4550b57cec5SDimitry Andric }
456