1 //===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/BinaryFormat/COFF.h" 14 #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" 15 #include "llvm/DebugInfo/MSF/MSFBuilder.h" 16 #include "llvm/DebugInfo/MSF/MSFCommon.h" 17 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 18 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" 19 #include "llvm/DebugInfo/PDB/Native/RawConstants.h" 20 #include "llvm/DebugInfo/PDB/Native/RawError.h" 21 #include "llvm/Support/BinaryItemStream.h" 22 #include "llvm/Support/BinaryStreamWriter.h" 23 24 using namespace llvm; 25 using namespace llvm::codeview; 26 using namespace llvm::msf; 27 using namespace llvm::pdb; 28 29 namespace llvm { 30 template <> struct BinaryItemTraits<CVSymbol> { 31 static size_t length(const CVSymbol &Item) { return Item.RecordData.size(); } 32 33 static ArrayRef<uint8_t> bytes(const CVSymbol &Item) { 34 return Item.RecordData; 35 } 36 }; 37 } 38 39 static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize, 40 uint32_t C13Size) { 41 uint32_t Size = sizeof(uint32_t); // Signature 42 Size += alignTo(SymbolByteSize, 4); // Symbol Data 43 Size += 0; // TODO: Layout.C11Bytes 44 Size += C13Size; // C13 Debug Info Size 45 Size += sizeof(uint32_t); // GlobalRefs substream size (always 0) 46 Size += 0; // GlobalRefs substream bytes 47 return Size; 48 } 49 50 DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName, 51 uint32_t ModIndex, 52 msf::MSFBuilder &Msf) 53 : MSF(Msf), ModuleName(ModuleName) { 54 Layout.Mod = ModIndex; 55 } 56 57 DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {} 58 59 uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const { 60 return Layout.ModDiStream; 61 } 62 63 void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) { 64 ObjFileName = Name; 65 } 66 67 void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) { 68 Symbols.push_back(Symbol); 69 // Symbols written to a PDB file are required to be 4 byte aligned. The same 70 // is not true of object files. 71 assert(Symbol.length() % alignOf(CodeViewContainer::Pdb) == 0 && 72 "Invalid Symbol alignment!"); 73 SymbolByteSize += Symbol.length(); 74 } 75 76 void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) { 77 SourceFiles.push_back(Path); 78 } 79 80 uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const { 81 uint32_t Result = 0; 82 for (const auto &Builder : C13Builders) { 83 assert(Builder && "Empty C13 Fragment Builder!"); 84 Result += Builder->calculateSerializedLength(); 85 } 86 return Result; 87 } 88 89 uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const { 90 uint32_t L = sizeof(Layout); 91 uint32_t M = ModuleName.size() + 1; 92 uint32_t O = ObjFileName.size() + 1; 93 return alignTo(L + M + O, sizeof(uint32_t)); 94 } 95 96 template <typename T> struct Foo { 97 explicit Foo(T &&Answer) : Answer(Answer) {} 98 99 T Answer; 100 }; 101 102 template <typename T> Foo<T> makeFoo(T &&t) { return Foo<T>(std::move(t)); } 103 104 void DbiModuleDescriptorBuilder::finalize() { 105 Layout.FileNameOffs = 0; // TODO: Fix this 106 Layout.Flags = 0; // TODO: Fix this 107 Layout.C11Bytes = 0; 108 Layout.C13Bytes = calculateC13DebugInfoSize(); 109 (void)Layout.Mod; // Set in constructor 110 (void)Layout.ModDiStream; // Set in finalizeMsfLayout 111 Layout.NumFiles = SourceFiles.size(); 112 Layout.PdbFilePathNI = 0; 113 Layout.SrcFileNameNI = 0; 114 115 // This value includes both the signature field as well as the record bytes 116 // from the symbol stream. 117 Layout.SymBytes = SymbolByteSize + sizeof(uint32_t); 118 } 119 120 Error DbiModuleDescriptorBuilder::finalizeMsfLayout() { 121 this->Layout.ModDiStream = kInvalidStreamIndex; 122 uint32_t C13Size = calculateC13DebugInfoSize(); 123 auto ExpectedSN = 124 MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); 125 if (!ExpectedSN) 126 return ExpectedSN.takeError(); 127 Layout.ModDiStream = *ExpectedSN; 128 return Error::success(); 129 } 130 131 Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter, 132 const msf::MSFLayout &MsfLayout, 133 WritableBinaryStreamRef MsfBuffer) { 134 // We write the Modi record to the `ModiWriter`, but we additionally write its 135 // symbol stream to a brand new stream. 136 if (auto EC = ModiWriter.writeObject(Layout)) 137 return EC; 138 if (auto EC = ModiWriter.writeCString(ModuleName)) 139 return EC; 140 if (auto EC = ModiWriter.writeCString(ObjFileName)) 141 return EC; 142 if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t))) 143 return EC; 144 145 if (Layout.ModDiStream != kInvalidStreamIndex) { 146 auto NS = WritableMappedBlockStream::createIndexedStream( 147 MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator()); 148 WritableBinaryStreamRef Ref(*NS); 149 BinaryStreamWriter SymbolWriter(Ref); 150 // Write the symbols. 151 if (auto EC = 152 SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC)) 153 return EC; 154 BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little); 155 Records.setItems(Symbols); 156 BinaryStreamRef RecordsRef(Records); 157 if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) 158 return EC; 159 if (auto EC = SymbolWriter.padToAlignment(4)) 160 return EC; 161 // TODO: Write C11 Line data 162 assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 && 163 "Invalid debug section alignment!"); 164 for (const auto &Builder : C13Builders) { 165 assert(Builder && "Empty C13 Fragment Builder!"); 166 if (auto EC = Builder->commit(SymbolWriter)) 167 return EC; 168 } 169 170 // TODO: Figure out what GlobalRefs substream actually is and populate it. 171 if (auto EC = SymbolWriter.writeInteger<uint32_t>(0)) 172 return EC; 173 if (SymbolWriter.bytesRemaining() > 0) 174 return make_error<RawError>(raw_error_code::stream_too_long); 175 } 176 return Error::success(); 177 } 178 179 void DbiModuleDescriptorBuilder::addDebugSubsection( 180 std::shared_ptr<DebugSubsection> Subsection) { 181 assert(Subsection); 182 C13Builders.push_back(llvm::make_unique<DebugSubsectionRecordBuilder>( 183 std::move(Subsection), CodeViewContainer::Pdb)); 184 } 185