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