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 assert(!Filename.empty()); 121 auto ExpectedLayout = finalizeMsfLayout(); 122 if (!ExpectedLayout) 123 return ExpectedLayout.takeError(); 124 auto &Layout = *ExpectedLayout; 125 126 uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; 127 auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); 128 if (OutFileOrError.getError()) 129 return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, 130 Filename); 131 FileBufferByteStream Buffer(std::move(*OutFileOrError), 132 llvm::support::little); 133 BinaryStreamWriter Writer(Buffer); 134 135 if (auto EC = Writer.writeObject(*Layout.SB)) 136 return EC; 137 uint32_t BlockMapOffset = 138 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); 139 Writer.setOffset(BlockMapOffset); 140 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) 141 return EC; 142 143 auto DirStream = WritableMappedBlockStream::createDirectoryStream( 144 Layout, Buffer, Allocator); 145 BinaryStreamWriter DW(*DirStream); 146 if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) 147 return EC; 148 149 if (auto EC = DW.writeArray(Layout.StreamSizes)) 150 return EC; 151 152 for (const auto &Blocks : Layout.StreamMap) { 153 if (auto EC = DW.writeArray(Blocks)) 154 return EC; 155 } 156 157 auto ExpectedSN = getNamedStreamIndex("/names"); 158 if (!ExpectedSN) 159 return ExpectedSN.takeError(); 160 161 auto NS = WritableMappedBlockStream::createIndexedStream( 162 Layout, Buffer, *ExpectedSN, Allocator); 163 BinaryStreamWriter NSWriter(*NS); 164 if (auto EC = Strings.commit(NSWriter)) 165 return EC; 166 167 if (Info) { 168 if (auto EC = Info->commit(Layout, Buffer)) 169 return EC; 170 } 171 172 if (Dbi) { 173 if (auto EC = Dbi->commit(Layout, Buffer)) 174 return EC; 175 } 176 177 if (Tpi) { 178 if (auto EC = Tpi->commit(Layout, Buffer)) 179 return EC; 180 } 181 182 if (Ipi) { 183 if (auto EC = Ipi->commit(Layout, Buffer)) 184 return EC; 185 } 186 187 return Buffer.commit(); 188 } 189