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