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/Raw/PDBFileBuilder.h" 11 12 #include "llvm/DebugInfo/CodeView/StreamInterface.h" 13 #include "llvm/DebugInfo/CodeView/StreamWriter.h" 14 #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" 15 #include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" 16 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" 17 #include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" 18 #include "llvm/DebugInfo/PDB/Raw/RawError.h" 19 20 using namespace llvm; 21 using namespace llvm::codeview; 22 using namespace llvm::pdb; 23 24 PDBFileBuilder::PDBFileBuilder( 25 std::unique_ptr<codeview::StreamInterface> PdbFileBuffer) 26 : File(llvm::make_unique<PDBFile>(std::move(PdbFileBuffer))) {} 27 28 Error PDBFileBuilder::setSuperBlock(const PDBFile::SuperBlock &B) { 29 auto SB = static_cast<PDBFile::SuperBlock *>( 30 File->Allocator.Allocate(sizeof(PDBFile::SuperBlock), 31 llvm::AlignOf<PDBFile::SuperBlock>::Alignment)); 32 ::memcpy(SB, &B, sizeof(PDBFile::SuperBlock)); 33 return File->setSuperBlock(SB); 34 } 35 36 void PDBFileBuilder::setStreamSizes(ArrayRef<support::ulittle32_t> S) { 37 File->StreamSizes = S; 38 } 39 40 void PDBFileBuilder::setDirectoryBlocks(ArrayRef<support::ulittle32_t> D) { 41 File->DirectoryBlocks = D; 42 } 43 44 void PDBFileBuilder::setStreamMap( 45 const std::vector<ArrayRef<support::ulittle32_t>> &S) { 46 File->StreamMap = S; 47 } 48 49 Error PDBFileBuilder::generateSimpleStreamMap() { 50 if (File->StreamSizes.empty()) 51 return Error::success(); 52 53 static std::vector<std::vector<support::ulittle32_t>> StaticMap; 54 File->StreamMap.clear(); 55 StaticMap.clear(); 56 57 // Figure out how many blocks are needed for all streams, and set the first 58 // used block to the highest block so that we can write the rest of the 59 // blocks contiguously. 60 uint32_t TotalFileBlocks = File->getBlockCount(); 61 std::vector<support::ulittle32_t> ReservedBlocks; 62 ReservedBlocks.push_back(support::ulittle32_t(0)); 63 ReservedBlocks.push_back(File->SB->BlockMapAddr); 64 ReservedBlocks.insert(ReservedBlocks.end(), File->DirectoryBlocks.begin(), 65 File->DirectoryBlocks.end()); 66 67 uint32_t BlocksNeeded = 0; 68 for (auto Size : File->StreamSizes) 69 BlocksNeeded += File->bytesToBlocks(Size, File->getBlockSize()); 70 71 support::ulittle32_t NextBlock(TotalFileBlocks - BlocksNeeded - 72 ReservedBlocks.size()); 73 74 StaticMap.resize(File->StreamSizes.size()); 75 for (uint32_t S = 0; S < File->StreamSizes.size(); ++S) { 76 uint32_t Size = File->StreamSizes[S]; 77 uint32_t NumBlocks = File->bytesToBlocks(Size, File->getBlockSize()); 78 auto &ThisStream = StaticMap[S]; 79 for (uint32_t I = 0; I < NumBlocks;) { 80 NextBlock += 1; 81 if (std::find(ReservedBlocks.begin(), ReservedBlocks.end(), NextBlock) != 82 ReservedBlocks.end()) 83 continue; 84 85 ++I; 86 assert(NextBlock < File->getBlockCount()); 87 ThisStream.push_back(NextBlock); 88 } 89 File->StreamMap.push_back(ThisStream); 90 } 91 return Error::success(); 92 } 93 94 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { 95 if (!Info) 96 Info = llvm::make_unique<InfoStreamBuilder>(*File); 97 return *Info; 98 } 99 100 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { 101 if (!Dbi) 102 Dbi = llvm::make_unique<DbiStreamBuilder>(*File); 103 return *Dbi; 104 } 105 106 Expected<std::unique_ptr<PDBFile>> PDBFileBuilder::build() { 107 if (Info) { 108 auto ExpectedInfo = Info->build(); 109 if (!ExpectedInfo) 110 return ExpectedInfo.takeError(); 111 File->Info = std::move(*ExpectedInfo); 112 } 113 114 if (Dbi) { 115 auto ExpectedDbi = Dbi->build(); 116 if (!ExpectedDbi) 117 return ExpectedDbi.takeError(); 118 File->Dbi = std::move(*ExpectedDbi); 119 } 120 121 if (File->Info && File->Dbi && File->Info->getAge() != File->Dbi->getAge()) 122 return llvm::make_error<RawError>( 123 raw_error_code::corrupt_file, 124 "PDB Stream Age doesn't match Dbi Stream Age!"); 125 126 return std::move(File); 127 } 128