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