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 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 (Gsi) { 126 if (auto EC = Gsi->finalizeMsfLayout()) 127 return std::move(EC); 128 if (Dbi) { 129 Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); 130 Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); 131 Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); 132 } 133 } 134 135 return Msf->build(); 136 } 137 138 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { 139 uint32_t SN = 0; 140 if (!NamedStreams.get(Name, SN)) 141 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); 142 return SN; 143 } 144 145 void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer, 146 const MSFLayout &Layout) { 147 auto FpmStream = 148 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator); 149 150 // We only need to create the alt fpm stream so that it gets initialized. 151 WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator, 152 true); 153 154 uint32_t BI = 0; 155 BinaryStreamWriter FpmWriter(*FpmStream); 156 while (BI < Layout.SB->NumBlocks) { 157 uint8_t ThisByte = 0; 158 for (uint32_t I = 0; I < 8; ++I) { 159 bool IsFree = 160 (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true; 161 uint8_t Mask = uint8_t(IsFree) << I; 162 ThisByte |= Mask; 163 ++BI; 164 } 165 cantFail(FpmWriter.writeObject(ThisByte)); 166 } 167 assert(FpmWriter.bytesRemaining() == 0); 168 } 169 170 Error PDBFileBuilder::commit(StringRef Filename) { 171 assert(!Filename.empty()); 172 auto ExpectedLayout = finalizeMsfLayout(); 173 if (!ExpectedLayout) 174 return ExpectedLayout.takeError(); 175 auto &Layout = *ExpectedLayout; 176 177 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; 178 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); 179 if (auto E = OutFileOrError.takeError()) 180 return E; 181 FileBufferByteStream Buffer(std::move(*OutFileOrError), 182 llvm::support::little); 183 BinaryStreamWriter Writer(Buffer); 184 185 if (auto EC = Writer.writeObject(*Layout.SB)) 186 return EC; 187 188 commitFpm(Buffer, Layout); 189 190 uint32_t BlockMapOffset = 191 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); 192 Writer.setOffset(BlockMapOffset); 193 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) 194 return EC; 195 196 auto DirStream = WritableMappedBlockStream::createDirectoryStream( 197 Layout, Buffer, Allocator); 198 BinaryStreamWriter DW(*DirStream); 199 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) 200 return EC; 201 202 if (auto EC = DW.writeArray(Layout.StreamSizes)) 203 return EC; 204 205 for (const auto &Blocks : Layout.StreamMap) { 206 if (auto EC = DW.writeArray(Blocks)) 207 return EC; 208 } 209 210 auto ExpectedSN = getNamedStreamIndex("/names"); 211 if (!ExpectedSN) 212 return ExpectedSN.takeError(); 213 214 auto NS = WritableMappedBlockStream::createIndexedStream( 215 Layout, Buffer, *ExpectedSN, Allocator); 216 BinaryStreamWriter NSWriter(*NS); 217 if (auto EC = Strings.commit(NSWriter)) 218 return EC; 219 220 if (Info) { 221 if (auto EC = Info->commit(Layout, Buffer)) 222 return EC; 223 } 224 225 if (Dbi) { 226 if (auto EC = Dbi->commit(Layout, Buffer)) 227 return EC; 228 } 229 230 if (Tpi) { 231 if (auto EC = Tpi->commit(Layout, Buffer)) 232 return EC; 233 } 234 235 if (Ipi) { 236 if (auto EC = Ipi->commit(Layout, Buffer)) 237 return EC; 238 } 239 240 if (Gsi) { 241 if (auto EC = Gsi->commit(Layout, Buffer)) 242 return EC; 243 } 244 245 return Buffer.commit(); 246 } 247