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" 21*5f757f3fSDimitry 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 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 350b57cec5SDimitry Andric void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; } 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric void DbiStreamBuilder::setAge(uint32_t A) { Age = A; } 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; } 400b57cec5SDimitry Andric 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 490b57cec5SDimitry Andric void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; } 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; } 560b57cec5SDimitry Andric 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 620b57cec5SDimitry Andric void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) { 630b57cec5SDimitry Andric GlobalsStreamIndex = Index; 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) { 670b57cec5SDimitry Andric SymRecordStreamIndex = Index; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) { 710b57cec5SDimitry Andric PublicsStreamIndex = Index; 720b57cec5SDimitry Andric } 730b57cec5SDimitry Andric 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 810b57cec5SDimitry Andric void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) { 820b57cec5SDimitry Andric OldFpoData.push_back(FD); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 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 980b57cec5SDimitry Andric uint32_t DbiStreamBuilder::addECName(StringRef Name) { 990b57cec5SDimitry Andric return ECNamesBuilder.insert(Name); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry 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 &> 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 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 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 1340b57cec5SDimitry 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 1410b57cec5SDimitry 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 1480b57cec5SDimitry 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 1540b57cec5SDimitry 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 1670b57cec5SDimitry 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 1730b57cec5SDimitry 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 1810b57cec5SDimitry Andric uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const { 1820b57cec5SDimitry Andric return DbgStreams.size() * sizeof(uint16_t); 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 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), 191*5f757f3fSDimitry 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 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 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 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. 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 3830b57cec5SDimitry Andric Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, 3840b57cec5SDimitry Andric WritableBinaryStreamRef MsfBuffer) { 385*5f757f3fSDimitry 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