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