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