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/DebugInfo/CodeView/ModuleDebugFragmentRecord.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/RawConstants.h" 19 #include "llvm/DebugInfo/PDB/Native/RawError.h" 20 #include "llvm/Support/BinaryItemStream.h" 21 #include "llvm/Support/BinaryStreamWriter.h" 22 #include "llvm/Support/COFF.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 += SymbolByteSize; // 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 SymbolByteSize += Symbol.data().size(); 70 } 71 72 void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) { 73 SourceFiles.push_back(Path); 74 } 75 76 uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const { 77 uint32_t Result = 0; 78 for (const auto &Builder : C13Builders) { 79 assert(Builder && "Empty C13 Fragment Builder!"); 80 Result += Builder->calculateSerializedLength(); 81 } 82 return Result; 83 } 84 85 uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const { 86 uint32_t L = sizeof(Layout); 87 uint32_t M = ModuleName.size() + 1; 88 uint32_t O = ObjFileName.size() + 1; 89 return alignTo(L + M + O, sizeof(uint32_t)); 90 } 91 92 template <typename T> struct Foo { 93 explicit Foo(T &&Answer) : Answer(Answer) {} 94 95 T Answer; 96 }; 97 98 template <typename T> Foo<T> makeFoo(T &&t) { return Foo<T>(std::move(t)); } 99 100 void DbiModuleDescriptorBuilder::finalize() { 101 Layout.FileNameOffs = 0; // TODO: Fix this 102 Layout.Flags = 0; // TODO: Fix this 103 Layout.C11Bytes = 0; 104 Layout.C13Bytes = calculateC13DebugInfoSize(); 105 (void)Layout.Mod; // Set in constructor 106 (void)Layout.ModDiStream; // Set in finalizeMsfLayout 107 Layout.NumFiles = SourceFiles.size(); 108 Layout.PdbFilePathNI = 0; 109 Layout.SrcFileNameNI = 0; 110 111 // This value includes both the signature field as well as the record bytes 112 // from the symbol stream. 113 Layout.SymBytes = SymbolByteSize + sizeof(uint32_t); 114 } 115 116 Error DbiModuleDescriptorBuilder::finalizeMsfLayout() { 117 this->Layout.ModDiStream = kInvalidStreamIndex; 118 uint32_t C13Size = calculateC13DebugInfoSize(); 119 auto ExpectedSN = 120 MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size)); 121 if (!ExpectedSN) 122 return ExpectedSN.takeError(); 123 Layout.ModDiStream = *ExpectedSN; 124 return Error::success(); 125 } 126 127 Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter, 128 const msf::MSFLayout &MsfLayout, 129 WritableBinaryStreamRef MsfBuffer) { 130 // We write the Modi record to the `ModiWriter`, but we additionally write its 131 // symbol stream to a brand new stream. 132 if (auto EC = ModiWriter.writeObject(Layout)) 133 return EC; 134 if (auto EC = ModiWriter.writeCString(ModuleName)) 135 return EC; 136 if (auto EC = ModiWriter.writeCString(ObjFileName)) 137 return EC; 138 if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t))) 139 return EC; 140 141 if (Layout.ModDiStream != kInvalidStreamIndex) { 142 auto NS = WritableMappedBlockStream::createIndexedStream( 143 MsfLayout, MsfBuffer, Layout.ModDiStream); 144 WritableBinaryStreamRef Ref(*NS); 145 BinaryStreamWriter SymbolWriter(Ref); 146 // Write the symbols. 147 if (auto EC = 148 SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC)) 149 return EC; 150 BinaryItemStream<CVSymbol> Records(llvm::support::endianness::little); 151 Records.setItems(Symbols); 152 BinaryStreamRef RecordsRef(Records); 153 if (auto EC = SymbolWriter.writeStreamRef(RecordsRef)) 154 return EC; 155 // TODO: Write C11 Line data 156 157 for (const auto &Builder : C13Builders) { 158 assert(Builder && "Empty C13 Fragment Builder!"); 159 if (auto EC = Builder->commit(SymbolWriter)) 160 return EC; 161 } 162 163 // TODO: Figure out what GlobalRefs substream actually is and populate it. 164 if (auto EC = SymbolWriter.writeInteger<uint32_t>(0)) 165 return EC; 166 if (SymbolWriter.bytesRemaining() > 0) 167 return make_error<RawError>(raw_error_code::stream_too_long); 168 } 169 return Error::success(); 170 } 171 172 void DbiModuleDescriptorBuilder::addC13Fragment( 173 std::unique_ptr<ModuleDebugLineFragment> Lines) { 174 ModuleDebugLineFragment &Frag = *Lines; 175 176 // File Checksums have to come first, so push an empty entry on if this 177 // is the first. 178 if (C13Builders.empty()) 179 C13Builders.push_back(nullptr); 180 181 this->LineInfo.push_back(std::move(Lines)); 182 C13Builders.push_back( 183 llvm::make_unique<ModuleDebugFragmentRecordBuilder>(Frag.kind(), Frag)); 184 } 185 186 void DbiModuleDescriptorBuilder::addC13Fragment( 187 std::unique_ptr<codeview::ModuleDebugInlineeLineFragment> Inlinees) { 188 ModuleDebugInlineeLineFragment &Frag = *Inlinees; 189 190 // File Checksums have to come first, so push an empty entry on if this 191 // is the first. 192 if (C13Builders.empty()) 193 C13Builders.push_back(nullptr); 194 195 this->Inlinees.push_back(std::move(Inlinees)); 196 C13Builders.push_back( 197 llvm::make_unique<ModuleDebugFragmentRecordBuilder>(Frag.kind(), Frag)); 198 } 199 200 void DbiModuleDescriptorBuilder::setC13FileChecksums( 201 std::unique_ptr<ModuleDebugFileChecksumFragment> Checksums) { 202 assert(!ChecksumInfo && "Can't have more than one checksum info!"); 203 204 if (C13Builders.empty()) 205 C13Builders.push_back(nullptr); 206 207 ChecksumInfo = std::move(Checksums); 208 C13Builders[0] = llvm::make_unique<ModuleDebugFragmentRecordBuilder>( 209 ChecksumInfo->kind(), *ChecksumInfo); 210 } 211