Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
35293 views
//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"910#include "llvm/ADT/ArrayRef.h"11#include "llvm/BinaryFormat/COFF.h"12#include "llvm/DebugInfo/CodeView/CodeView.h"13#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"14#include "llvm/DebugInfo/MSF/MSFBuilder.h"15#include "llvm/DebugInfo/MSF/MappedBlockStream.h"16#include "llvm/DebugInfo/PDB/Native/RawConstants.h"17#include "llvm/DebugInfo/PDB/Native/RawError.h"18#include "llvm/Support/BinaryStreamWriter.h"1920using namespace llvm;21using namespace llvm::codeview;22using namespace llvm::msf;23using namespace llvm::pdb;2425namespace llvm {26namespace codeview {27class DebugSubsection;28}29} // namespace llvm3031static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,32uint32_t C13Size) {33uint32_t Size = sizeof(uint32_t); // Signature34Size += alignTo(SymbolByteSize, 4); // Symbol Data35Size += 0; // TODO: Layout.C11Bytes36Size += C13Size; // C13 Debug Info Size37Size += sizeof(uint32_t); // GlobalRefs substream size (always 0)38Size += 0; // GlobalRefs substream bytes39return Size;40}4142DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName,43uint32_t ModIndex,44msf::MSFBuilder &Msf)45: MSF(Msf), ModuleName(std::string(ModuleName)) {46::memset(&Layout, 0, sizeof(Layout));47Layout.Mod = ModIndex;48}4950DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() = default;5152uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const {53return Layout.ModDiStream;54}5556void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {57ObjFileName = std::string(Name);58}5960void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) {61PdbFilePathNI = NI;62}6364void DbiModuleDescriptorBuilder::setFirstSectionContrib(65const SectionContrib &SC) {66Layout.SC = SC;67}6869void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {70// Defer to the bulk API. It does the same thing.71addSymbolsInBulk(Symbol.data());72}7374void DbiModuleDescriptorBuilder::addSymbolsInBulk(75ArrayRef<uint8_t> BulkSymbols) {76// Do nothing for empty runs of symbols.77if (BulkSymbols.empty())78return;7980Symbols.push_back(SymbolListWrapper(BulkSymbols));81// Symbols written to a PDB file are required to be 4 byte aligned. The same82// is not true of object files.83assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 &&84"Invalid Symbol alignment!");85SymbolByteSize += BulkSymbols.size();86}8788void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc,89uint32_t SymLength) {90assert(SymLength > 0);91Symbols.push_back(SymbolListWrapper(SymSrc, SymLength));9293// Symbols written to a PDB file are required to be 4 byte aligned. The same94// is not true of object files.95assert(SymLength % alignOf(CodeViewContainer::Pdb) == 0 &&96"Invalid Symbol alignment!");97SymbolByteSize += SymLength;98}99100void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {101SourceFiles.push_back(std::string(Path));102}103104uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const {105uint32_t Result = 0;106for (const auto &Builder : C13Builders) {107Result += Builder.calculateSerializedLength();108}109return Result;110}111112uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {113uint32_t L = sizeof(Layout);114uint32_t M = ModuleName.size() + 1;115uint32_t O = ObjFileName.size() + 1;116return alignTo(L + M + O, sizeof(uint32_t));117}118119void DbiModuleDescriptorBuilder::finalize() {120Layout.FileNameOffs = 0; // TODO: Fix this121Layout.Flags = 0; // TODO: Fix this122Layout.C11Bytes = 0;123Layout.C13Bytes = calculateC13DebugInfoSize();124(void)Layout.Mod; // Set in constructor125(void)Layout.ModDiStream; // Set in finalizeMsfLayout126Layout.NumFiles = SourceFiles.size();127Layout.PdbFilePathNI = PdbFilePathNI;128Layout.SrcFileNameNI = 0;129130// This value includes both the signature field as well as the record bytes131// from the symbol stream.132Layout.SymBytes =133Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset();134}135136Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {137this->Layout.ModDiStream = kInvalidStreamIndex;138uint32_t C13Size = calculateC13DebugInfoSize();139if (!C13Size && !SymbolByteSize)140return Error::success();141auto ExpectedSN =142MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size));143if (!ExpectedSN)144return ExpectedSN.takeError();145Layout.ModDiStream = *ExpectedSN;146return Error::success();147}148149Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) {150// We write the Modi record to the `ModiWriter`, but we additionally write its151// symbol stream to a brand new stream.152if (auto EC = ModiWriter.writeObject(Layout))153return EC;154if (auto EC = ModiWriter.writeCString(ModuleName))155return EC;156if (auto EC = ModiWriter.writeCString(ObjFileName))157return EC;158if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))159return EC;160return Error::success();161}162163Error DbiModuleDescriptorBuilder::commitSymbolStream(164const msf::MSFLayout &MsfLayout, WritableBinaryStreamRef MsfBuffer) {165if (Layout.ModDiStream == kInvalidStreamIndex)166return Error::success();167168auto NS = WritableMappedBlockStream::createIndexedStream(169MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());170WritableBinaryStreamRef Ref(*NS);171BinaryStreamWriter SymbolWriter(Ref);172// Write the symbols.173if (auto EC = SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))174return EC;175for (const SymbolListWrapper &Sym : Symbols) {176if (Sym.NeedsToBeMerged) {177assert(MergeSymsCallback);178if (auto EC = MergeSymsCallback(MergeSymsCtx, Sym.SymPtr, SymbolWriter))179return EC;180} else {181if (auto EC = SymbolWriter.writeBytes(Sym.asArray()))182return EC;183}184}185186// Apply the string table fixups.187auto SavedOffset = SymbolWriter.getOffset();188for (const StringTableFixup &Fixup : StringTableFixups) {189SymbolWriter.setOffset(Fixup.SymOffsetOfReference);190if (auto E = SymbolWriter.writeInteger<uint32_t>(Fixup.StrTabOffset))191return E;192}193SymbolWriter.setOffset(SavedOffset);194195assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&196"Invalid debug section alignment!");197// TODO: Write C11 Line data198for (const auto &Builder : C13Builders) {199if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb))200return EC;201}202203// TODO: Figure out what GlobalRefs substream actually is and populate it.204if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))205return EC;206if (SymbolWriter.bytesRemaining() > 0)207return make_error<RawError>(raw_error_code::stream_too_long);208209return Error::success();210}211212void DbiModuleDescriptorBuilder::addDebugSubsection(213std::shared_ptr<DebugSubsection> Subsection) {214assert(Subsection);215C13Builders.push_back(DebugSubsectionRecordBuilder(std::move(Subsection)));216}217218void DbiModuleDescriptorBuilder::addDebugSubsection(219const DebugSubsectionRecord &SubsectionContents) {220C13Builders.push_back(DebugSubsectionRecordBuilder(SubsectionContents));221}222223224