223 lines · cpp
1//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"10 11#include "llvm/ADT/ArrayRef.h"12#include "llvm/BinaryFormat/COFF.h"13#include "llvm/DebugInfo/CodeView/CodeView.h"14#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"15#include "llvm/DebugInfo/MSF/MSFBuilder.h"16#include "llvm/DebugInfo/MSF/MappedBlockStream.h"17#include "llvm/DebugInfo/PDB/Native/RawConstants.h"18#include "llvm/DebugInfo/PDB/Native/RawError.h"19#include "llvm/Support/BinaryStreamWriter.h"20 21using namespace llvm;22using namespace llvm::codeview;23using namespace llvm::msf;24using namespace llvm::pdb;25 26namespace llvm {27namespace codeview {28class DebugSubsection;29}30} // namespace llvm31 32static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,33 uint32_t C13Size) {34 uint32_t Size = sizeof(uint32_t); // Signature35 Size += alignTo(SymbolByteSize, 4); // Symbol Data36 Size += 0; // TODO: Layout.C11Bytes37 Size += C13Size; // C13 Debug Info Size38 Size += sizeof(uint32_t); // GlobalRefs substream size (always 0)39 Size += 0; // GlobalRefs substream bytes40 return Size;41}42 43DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName,44 uint32_t ModIndex,45 msf::MSFBuilder &Msf)46 : MSF(Msf), ModuleName(std::string(ModuleName)) {47 ::memset(&Layout, 0, sizeof(Layout));48 Layout.Mod = ModIndex;49}50 51DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() = default;52 53uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const {54 return Layout.ModDiStream;55}56 57void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {58 ObjFileName = std::string(Name);59}60 61void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) {62 PdbFilePathNI = NI;63}64 65void DbiModuleDescriptorBuilder::setFirstSectionContrib(66 const SectionContrib &SC) {67 Layout.SC = SC;68}69 70void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {71 // Defer to the bulk API. It does the same thing.72 addSymbolsInBulk(Symbol.data());73}74 75void DbiModuleDescriptorBuilder::addSymbolsInBulk(76 ArrayRef<uint8_t> BulkSymbols) {77 // Do nothing for empty runs of symbols.78 if (BulkSymbols.empty())79 return;80 81 Symbols.push_back(SymbolListWrapper(BulkSymbols));82 // Symbols written to a PDB file are required to be 4 byte aligned. The same83 // is not true of object files.84 assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 &&85 "Invalid Symbol alignment!");86 SymbolByteSize += BulkSymbols.size();87}88 89void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc,90 uint32_t SymLength) {91 assert(SymLength > 0);92 Symbols.push_back(SymbolListWrapper(SymSrc, SymLength));93 94 // Symbols written to a PDB file are required to be 4 byte aligned. The same95 // is not true of object files.96 assert(SymLength % alignOf(CodeViewContainer::Pdb) == 0 &&97 "Invalid Symbol alignment!");98 SymbolByteSize += SymLength;99}100 101void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {102 SourceFiles.push_back(std::string(Path));103}104 105uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const {106 uint32_t Result = 0;107 for (const auto &Builder : C13Builders) {108 Result += Builder.calculateSerializedLength();109 }110 return Result;111}112 113uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {114 uint32_t L = sizeof(Layout);115 uint32_t M = ModuleName.size() + 1;116 uint32_t O = ObjFileName.size() + 1;117 return alignTo(L + M + O, sizeof(uint32_t));118}119 120void DbiModuleDescriptorBuilder::finalize() {121 Layout.FileNameOffs = 0; // TODO: Fix this122 Layout.Flags = 0; // TODO: Fix this123 Layout.C11Bytes = 0;124 Layout.C13Bytes = calculateC13DebugInfoSize();125 (void)Layout.Mod; // Set in constructor126 (void)Layout.ModDiStream; // Set in finalizeMsfLayout127 Layout.NumFiles = SourceFiles.size();128 Layout.PdbFilePathNI = PdbFilePathNI;129 Layout.SrcFileNameNI = 0;130 131 // This value includes both the signature field as well as the record bytes132 // from the symbol stream.133 Layout.SymBytes =134 Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset();135}136 137Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {138 this->Layout.ModDiStream = kInvalidStreamIndex;139 uint32_t C13Size = calculateC13DebugInfoSize();140 if (!C13Size && !SymbolByteSize)141 return Error::success();142 auto ExpectedSN =143 MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size));144 if (!ExpectedSN)145 return ExpectedSN.takeError();146 Layout.ModDiStream = *ExpectedSN;147 return Error::success();148}149 150Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) {151 // We write the Modi record to the `ModiWriter`, but we additionally write its152 // symbol stream to a brand new stream.153 if (auto EC = ModiWriter.writeObject(Layout))154 return EC;155 if (auto EC = ModiWriter.writeCString(ModuleName))156 return EC;157 if (auto EC = ModiWriter.writeCString(ObjFileName))158 return EC;159 if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))160 return EC;161 return Error::success();162}163 164Error DbiModuleDescriptorBuilder::commitSymbolStream(165 const msf::MSFLayout &MsfLayout, WritableBinaryStreamRef MsfBuffer) {166 if (Layout.ModDiStream == kInvalidStreamIndex)167 return Error::success();168 169 auto NS = WritableMappedBlockStream::createIndexedStream(170 MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());171 WritableBinaryStreamRef Ref(*NS);172 BinaryStreamWriter SymbolWriter(Ref);173 // Write the symbols.174 if (auto EC = SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))175 return EC;176 for (const SymbolListWrapper &Sym : Symbols) {177 if (Sym.NeedsToBeMerged) {178 assert(MergeSymsCallback);179 if (auto EC = MergeSymsCallback(MergeSymsCtx, Sym.SymPtr, SymbolWriter))180 return EC;181 } else {182 if (auto EC = SymbolWriter.writeBytes(Sym.asArray()))183 return EC;184 }185 }186 187 // Apply the string table fixups.188 auto SavedOffset = SymbolWriter.getOffset();189 for (const StringTableFixup &Fixup : StringTableFixups) {190 SymbolWriter.setOffset(Fixup.SymOffsetOfReference);191 if (auto E = SymbolWriter.writeInteger<uint32_t>(Fixup.StrTabOffset))192 return E;193 }194 SymbolWriter.setOffset(SavedOffset);195 196 assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&197 "Invalid debug section alignment!");198 // TODO: Write C11 Line data199 for (const auto &Builder : C13Builders) {200 if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb))201 return EC;202 }203 204 // TODO: Figure out what GlobalRefs substream actually is and populate it.205 if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))206 return EC;207 if (SymbolWriter.bytesRemaining() > 0)208 return make_error<RawError>(raw_error_code::stream_too_long);209 210 return Error::success();211}212 213void DbiModuleDescriptorBuilder::addDebugSubsection(214 std::shared_ptr<DebugSubsection> Subsection) {215 assert(Subsection);216 C13Builders.push_back(DebugSubsectionRecordBuilder(std::move(Subsection)));217}218 219void DbiModuleDescriptorBuilder::addDebugSubsection(220 const DebugSubsectionRecord &SubsectionContents) {221 C13Builders.push_back(DebugSubsectionRecordBuilder(SubsectionContents));222}223