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 100 if (Info) { 101 if (auto EC = Info->finalizeMsfLayout()) 102 return std::move(EC); 103 } 104 if (Dbi) { 105 if (auto EC = Dbi->finalizeMsfLayout()) 106 return std::move(EC); 107 } 108 if (Tpi) { 109 if (auto EC = Tpi->finalizeMsfLayout()) 110 return std::move(EC); 111 } 112 if (Ipi) { 113 if (auto EC = Ipi->finalizeMsfLayout()) 114 return std::move(EC); 115 } 116 117 return Msf->build(); 118 } 119 120 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { 121 uint32_t SN = 0; 122 if (!NamedStreams.get(Name, SN)) 123 return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); 124 return SN; 125 } 126 127 Error PDBFileBuilder::commit(StringRef Filename) { 128 assert(!Filename.empty()); 129 auto ExpectedLayout = finalizeMsfLayout(); 130 if (!ExpectedLayout) 131 return ExpectedLayout.takeError(); 132 auto &Layout = *ExpectedLayout; 133 134 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; 135 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); 136 if (OutFileOrError.getError()) 137 return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, 138 Filename); 139 FileBufferByteStream Buffer(std::move(*OutFileOrError), 140 llvm::support::little); 141 BinaryStreamWriter Writer(Buffer); 142 143 if (auto EC = Writer.writeObject(*Layout.SB)) 144 return EC; 145 uint32_t BlockMapOffset = 146 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); 147 Writer.setOffset(BlockMapOffset); 148 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) 149 return EC; 150 151 auto DirStream = WritableMappedBlockStream::createDirectoryStream( 152 Layout, Buffer, Allocator); 153 BinaryStreamWriter DW(*DirStream); 154 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) 155 return EC; 156 157 if (auto EC = DW.writeArray(Layout.StreamSizes)) 158 return EC; 159 160 for (const auto &Blocks : Layout.StreamMap) { 161 if (auto EC = DW.writeArray(Blocks)) 162 return EC; 163 } 164 165 auto ExpectedSN = getNamedStreamIndex("/names"); 166 if (!ExpectedSN) 167 return ExpectedSN.takeError(); 168 169 auto NS = WritableMappedBlockStream::createIndexedStream( 170 Layout, Buffer, *ExpectedSN, Allocator); 171 BinaryStreamWriter NSWriter(*NS); 172 if (auto EC = Strings.commit(NSWriter)) 173 return EC; 174 175 if (Info) { 176 if (auto EC = Info->commit(Layout, Buffer)) 177 return EC; 178 } 179 180 if (Dbi) { 181 if (auto EC = Dbi->commit(Layout, Buffer)) 182 return EC; 183 } 184 185 if (Tpi) { 186 if (auto EC = Tpi->commit(Layout, Buffer)) 187 return EC; 188 } 189 190 if (Ipi) { 191 if (auto EC = Ipi->commit(Layout, Buffer)) 192 return EC; 193 } 194 195 return Buffer.commit(); 196 } 197