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/GSIStreamBuilder.h" 19 #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 20 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" 21 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.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 GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { 78 if (!Gsi) 79 Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf); 80 return *Gsi; 81 } 82 83 Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name, 84 uint32_t Size) { 85 auto ExpectedStream = Msf->addStream(Size); 86 if (ExpectedStream) 87 NamedStreams.set(Name, *ExpectedStream); 88 return ExpectedStream; 89 } 90 91 Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) { 92 Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size()); 93 if (!ExpectedIndex) 94 return ExpectedIndex.takeError(); 95 assert(NamedStreamData.count(*ExpectedIndex) == 0); 96 NamedStreamData[*ExpectedIndex] = Data; 97 return Error::success(); 98 } 99 100 Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { 101 102 if (Ipi && Ipi->getRecordCount() > 0) { 103 // In theory newer PDBs always have an ID stream, but by saying that we're 104 // only going to *really* have an ID stream if there is at least one ID 105 // record, we leave open the opportunity to test older PDBs such as those 106 // that don't have an ID stream. 107 auto &Info = getInfoBuilder(); 108 Info.addFeature(PdbRaw_FeatureSig::VC140); 109 } 110 111 uint32_t StringsLen = Strings.calculateSerializedSize(); 112 113 Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0); 114 if (!SN) 115 return SN.takeError(); 116 117 if (Gsi) { 118 if (auto EC = Gsi->finalizeMsfLayout()) 119 return std::move(EC); 120 if (Dbi) { 121 Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); 122 Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); 123 Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); 124 } 125 } 126 if (Tpi) { 127 if (auto EC = Tpi->finalizeMsfLayout()) 128 return std::move(EC); 129 } 130 if (Dbi) { 131 if (auto EC = Dbi->finalizeMsfLayout()) 132 return std::move(EC); 133 } 134 SN = allocateNamedStream("/names", StringsLen); 135 if (!SN) 136 return SN.takeError(); 137 138 if (Ipi) { 139 if (auto EC = Ipi->finalizeMsfLayout()) 140 return std::move(EC); 141 } 142 143 // Do this last, since it relies on the named stream map being complete, and 144 // that can be updated by previous steps in the finalization. 145 if (Info) { 146 if (auto EC = Info->finalizeMsfLayout()) 147 return std::move(EC); 148 } 149 150 return Msf->build(); 151 } 152 153 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { 154 uint32_t SN = 0; 155 if (!NamedStreams.get(Name, SN)) 156 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); 157 return SN; 158 } 159 160 void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer, 161 const MSFLayout &Layout) { 162 auto FpmStream = 163 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator); 164 165 // We only need to create the alt fpm stream so that it gets initialized. 166 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator, 167 true); 168 169 uint32_t BI = 0; 170 BinaryStreamWriter FpmWriter(*FpmStream); 171 while (BI < Layout.SB->NumBlocks) { 172 uint8_t ThisByte = 0; 173 for (uint32_t I = 0; I < 8; ++I) { 174 bool IsFree = 175 (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true; 176 uint8_t Mask = uint8_t(IsFree) << I; 177 ThisByte |= Mask; 178 ++BI; 179 } 180 cantFail(FpmWriter.writeObject(ThisByte)); 181 } 182 assert(FpmWriter.bytesRemaining() == 0); 183 } 184 185 Error PDBFileBuilder::commit(StringRef Filename) { 186 assert(!Filename.empty()); 187 auto ExpectedLayout = finalizeMsfLayout(); 188 if (!ExpectedLayout) 189 return ExpectedLayout.takeError(); 190 auto &Layout = *ExpectedLayout; 191 192 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; 193 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); 194 if (auto E = OutFileOrError.takeError()) 195 return E; 196 FileOutputBuffer *FOB = OutFileOrError->get(); 197 198 FileBufferByteStream Buffer(std::move(*OutFileOrError), 199 llvm::support::little); 200 BinaryStreamWriter Writer(Buffer); 201 202 if (auto EC = Writer.writeObject(*Layout.SB)) 203 return EC; 204 205 commitFpm(Buffer, Layout); 206 207 uint32_t BlockMapOffset = 208 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); 209 Writer.setOffset(BlockMapOffset); 210 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) 211 return EC; 212 213 auto DirStream = WritableMappedBlockStream::createDirectoryStream( 214 Layout, Buffer, Allocator); 215 BinaryStreamWriter DW(*DirStream); 216 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) 217 return EC; 218 219 if (auto EC = DW.writeArray(Layout.StreamSizes)) 220 return EC; 221 222 for (const auto &Blocks : Layout.StreamMap) { 223 if (auto EC = DW.writeArray(Blocks)) 224 return EC; 225 } 226 227 auto ExpectedSN = getNamedStreamIndex("/names"); 228 if (!ExpectedSN) 229 return ExpectedSN.takeError(); 230 231 auto NS = WritableMappedBlockStream::createIndexedStream( 232 Layout, Buffer, *ExpectedSN, Allocator); 233 BinaryStreamWriter NSWriter(*NS); 234 if (auto EC = Strings.commit(NSWriter)) 235 return EC; 236 237 for (const auto &NSE : NamedStreamData) { 238 if (NSE.second.empty()) 239 continue; 240 241 auto NS = WritableMappedBlockStream::createIndexedStream( 242 Layout, Buffer, NSE.first, Allocator); 243 BinaryStreamWriter NSW(*NS); 244 if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second))) 245 return EC; 246 } 247 248 if (Info) { 249 if (auto EC = Info->commit(Layout, Buffer)) 250 return EC; 251 } 252 253 if (Dbi) { 254 if (auto EC = Dbi->commit(Layout, Buffer)) 255 return EC; 256 } 257 258 if (Tpi) { 259 if (auto EC = Tpi->commit(Layout, Buffer)) 260 return EC; 261 } 262 263 if (Ipi) { 264 if (auto EC = Ipi->commit(Layout, Buffer)) 265 return EC; 266 } 267 268 if (Gsi) { 269 if (auto EC = Gsi->commit(Layout, Buffer)) 270 return EC; 271 } 272 273 auto InfoStreamBlocks = Layout.StreamMap[StreamPDB]; 274 assert(!InfoStreamBlocks.empty()); 275 uint64_t InfoStreamFileOffset = 276 blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize); 277 InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>( 278 FOB->getBufferStart() + InfoStreamFileOffset); 279 280 // Set the build id at the very end, after every other byte of the PDB 281 // has been written. 282 // FIXME: Use a hash of the PDB rather than time(nullptr) for the signature. 283 H->Age = Info->getAge(); 284 H->Guid = Info->getGuid(); 285 Optional<uint32_t> Sig = Info->getSignature(); 286 H->Signature = Sig.hasValue() ? *Sig : time(nullptr); 287 288 return Buffer.commit(); 289 } 290