1 //===- PDBFileBuilder.cpp - PDB File 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/PDBFileBuilder.h" 11 12 #include "llvm/ADT/BitVector.h" 13 14 #include "llvm/DebugInfo/MSF/MSFBuilder.h" 15 #include "llvm/DebugInfo/PDB/GenericError.h" 16 #include "llvm/DebugInfo/PDB/Native/DbiStream.h" 17 #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" 18 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 19 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" 20 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" 21 #include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h" 22 #include "llvm/DebugInfo/PDB/Native/RawError.h" 23 #include "llvm/DebugInfo/PDB/Native/TpiStream.h" 24 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" 25 #include "llvm/Support/BinaryStream.h" 26 #include "llvm/Support/BinaryStreamWriter.h" 27 28 using namespace llvm; 29 using namespace llvm::codeview; 30 using namespace llvm::msf; 31 using namespace llvm::pdb; 32 using namespace llvm::support; 33 34 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) 35 : Allocator(Allocator) {} 36 37 PDBFileBuilder::~PDBFileBuilder() {} 38 39 Error PDBFileBuilder::initialize(uint32_t BlockSize) { 40 auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); 41 if (!ExpectedMsf) 42 return ExpectedMsf.takeError(); 43 Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); 44 return Error::success(); 45 } 46 47 MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } 48 49 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { 50 if (!Info) 51 Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); 52 return *Info; 53 } 54 55 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { 56 if (!Dbi) 57 Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf); 58 return *Dbi; 59 } 60 61 TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { 62 if (!Tpi) 63 Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); 64 return *Tpi; 65 } 66 67 TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { 68 if (!Ipi) 69 Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); 70 return *Ipi; 71 } 72 73 PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { 74 return Strings; 75 } 76 77 PublicsStreamBuilder &PDBFileBuilder::getPublicsBuilder() { 78 if (!Publics) 79 Publics = llvm::make_unique<PublicsStreamBuilder>(*Msf); 80 return *Publics; 81 } 82 83 Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { 84 auto ExpectedStream = Msf->addStream(Size); 85 if (!ExpectedStream) 86 return ExpectedStream.takeError(); 87 NamedStreams.set(Name, *ExpectedStream); 88 return Error::success(); 89 } 90 91 Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { 92 93 if (Ipi && Ipi->getRecordCount() > 0) { 94 // In theory newer PDBs always have an ID stream, but by saying that we're 95 // only going to *really* have an ID stream if there is at least one ID 96 // record, we leave open the opportunity to test older PDBs such as those 97 // that don't have an ID stream. 98 auto &Info = getInfoBuilder(); 99 Info.addFeature(PdbRaw_FeatureSig::VC140); 100 } 101 102 uint32_t StringsLen = Strings.calculateSerializedSize(); 103 104 if (auto EC = addNamedStream("/names", StringsLen)) 105 return std::move(EC); 106 if (auto EC = addNamedStream("/LinkInfo", 0)) 107 return std::move(EC); 108 109 if (Info) { 110 if (auto EC = Info->finalizeMsfLayout()) 111 return std::move(EC); 112 } 113 if (Dbi) { 114 if (auto EC = Dbi->finalizeMsfLayout()) 115 return std::move(EC); 116 } 117 if (Tpi) { 118 if (auto EC = Tpi->finalizeMsfLayout()) 119 return std::move(EC); 120 } 121 if (Ipi) { 122 if (auto EC = Ipi->finalizeMsfLayout()) 123 return std::move(EC); 124 } 125 if (Publics) { 126 if (auto EC = Publics->finalizeMsfLayout()) 127 return std::move(EC); 128 if (Dbi) { 129 Dbi->setPublicsStreamIndex(Publics->getStreamIndex()); 130 Dbi->setSymbolRecordStreamIndex(Publics->getRecordStreamIdx()); 131 } 132 } 133 134 return Msf->build(); 135 } 136 137 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { 138 uint32_t SN = 0; 139 if (!NamedStreams.get(Name, SN)) 140 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); 141 return SN; 142 } 143 144 Error PDBFileBuilder::commit(StringRef Filename) { 145 assert(!Filename.empty()); 146 auto ExpectedLayout = finalizeMsfLayout(); 147 if (!ExpectedLayout) 148 return ExpectedLayout.takeError(); 149 auto &Layout = *ExpectedLayout; 150 151 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; 152 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); 153 if (OutFileOrError.getError()) 154 return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, 155 Filename); 156 FileBufferByteStream Buffer(std::move(*OutFileOrError), 157 llvm::support::little); 158 BinaryStreamWriter Writer(Buffer); 159 160 if (auto EC = Writer.writeObject(*Layout.SB)) 161 return EC; 162 uint32_t BlockMapOffset = 163 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); 164 Writer.setOffset(BlockMapOffset); 165 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) 166 return EC; 167 168 auto DirStream = WritableMappedBlockStream::createDirectoryStream( 169 Layout, Buffer, Allocator); 170 BinaryStreamWriter DW(*DirStream); 171 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) 172 return EC; 173 174 if (auto EC = DW.writeArray(Layout.StreamSizes)) 175 return EC; 176 177 for (const auto &Blocks : Layout.StreamMap) { 178 if (auto EC = DW.writeArray(Blocks)) 179 return EC; 180 } 181 182 auto ExpectedSN = getNamedStreamIndex("/names"); 183 if (!ExpectedSN) 184 return ExpectedSN.takeError(); 185 186 auto NS = WritableMappedBlockStream::createIndexedStream( 187 Layout, Buffer, *ExpectedSN, Allocator); 188 BinaryStreamWriter NSWriter(*NS); 189 if (auto EC = Strings.commit(NSWriter)) 190 return EC; 191 192 if (Info) { 193 if (auto EC = Info->commit(Layout, Buffer)) 194 return EC; 195 } 196 197 if (Dbi) { 198 if (auto EC = Dbi->commit(Layout, Buffer)) 199 return EC; 200 } 201 202 if (Tpi) { 203 if (auto EC = Tpi->commit(Layout, Buffer)) 204 return EC; 205 } 206 207 if (Ipi) { 208 if (auto EC = Ipi->commit(Layout, Buffer)) 209 return EC; 210 } 211 212 if (Publics) { 213 auto PS = WritableMappedBlockStream::createIndexedStream( 214 Layout, Buffer, Publics->getStreamIndex(), Allocator); 215 auto PRS = WritableMappedBlockStream::createIndexedStream( 216 Layout, Buffer, Publics->getRecordStreamIdx(), Allocator); 217 BinaryStreamWriter PSWriter(*PS); 218 BinaryStreamWriter RecWriter(*PRS); 219 if (auto EC = Publics->commit(PSWriter, RecWriter)) 220 return EC; 221 } 222 223 return Buffer.commit(); 224 } 225