| //===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h" |
| |
| #include "llvm/DebugInfo/CodeView/StreamInterface.h" |
| #include "llvm/DebugInfo/CodeView/StreamWriter.h" |
| #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" |
| #include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" |
| #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" |
| #include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" |
| #include "llvm/DebugInfo/PDB/Raw/RawError.h" |
| |
| using namespace llvm; |
| using namespace llvm::codeview; |
| using namespace llvm::pdb; |
| |
| PDBFileBuilder::PDBFileBuilder( |
| std::unique_ptr<codeview::StreamInterface> PdbFileBuffer) |
| : File(llvm::make_unique<PDBFile>(std::move(PdbFileBuffer))) {} |
| |
| Error PDBFileBuilder::setSuperBlock(const PDBFile::SuperBlock &B) { |
| auto SB = static_cast<PDBFile::SuperBlock *>( |
| File->Allocator.Allocate(sizeof(PDBFile::SuperBlock), |
| llvm::AlignOf<PDBFile::SuperBlock>::Alignment)); |
| ::memcpy(SB, &B, sizeof(PDBFile::SuperBlock)); |
| return File->setSuperBlock(SB); |
| } |
| |
| void PDBFileBuilder::setStreamSizes(ArrayRef<support::ulittle32_t> S) { |
| File->StreamSizes = S; |
| } |
| |
| void PDBFileBuilder::setDirectoryBlocks(ArrayRef<support::ulittle32_t> D) { |
| File->DirectoryBlocks = D; |
| } |
| |
| void PDBFileBuilder::setStreamMap( |
| const std::vector<ArrayRef<support::ulittle32_t>> &S) { |
| File->StreamMap = S; |
| } |
| |
| Error PDBFileBuilder::generateSimpleStreamMap() { |
| if (File->StreamSizes.empty()) |
| return Error::success(); |
| |
| static std::vector<std::vector<support::ulittle32_t>> StaticMap; |
| File->StreamMap.clear(); |
| StaticMap.clear(); |
| |
| // Figure out how many blocks are needed for all streams, and set the first |
| // used block to the highest block so that we can write the rest of the |
| // blocks contiguously. |
| uint32_t TotalFileBlocks = File->getBlockCount(); |
| std::vector<support::ulittle32_t> ReservedBlocks; |
| ReservedBlocks.push_back(support::ulittle32_t(0)); |
| ReservedBlocks.push_back(File->SB->BlockMapAddr); |
| ReservedBlocks.insert(ReservedBlocks.end(), File->DirectoryBlocks.begin(), |
| File->DirectoryBlocks.end()); |
| |
| uint32_t BlocksNeeded = 0; |
| for (auto Size : File->StreamSizes) |
| BlocksNeeded += File->bytesToBlocks(Size, File->getBlockSize()); |
| |
| support::ulittle32_t NextBlock(TotalFileBlocks - BlocksNeeded - |
| ReservedBlocks.size()); |
| |
| StaticMap.resize(File->StreamSizes.size()); |
| for (uint32_t S = 0; S < File->StreamSizes.size(); ++S) { |
| uint32_t Size = File->StreamSizes[S]; |
| uint32_t NumBlocks = File->bytesToBlocks(Size, File->getBlockSize()); |
| auto &ThisStream = StaticMap[S]; |
| for (uint32_t I = 0; I < NumBlocks;) { |
| NextBlock += 1; |
| if (std::find(ReservedBlocks.begin(), ReservedBlocks.end(), NextBlock) != |
| ReservedBlocks.end()) |
| continue; |
| |
| ++I; |
| assert(NextBlock < File->getBlockCount()); |
| ThisStream.push_back(NextBlock); |
| } |
| File->StreamMap.push_back(ThisStream); |
| } |
| return Error::success(); |
| } |
| |
| InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { |
| if (!Info) |
| Info = llvm::make_unique<InfoStreamBuilder>(*File); |
| return *Info; |
| } |
| |
| DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { |
| if (!Dbi) |
| Dbi = llvm::make_unique<DbiStreamBuilder>(*File); |
| return *Dbi; |
| } |
| |
| Expected<std::unique_ptr<PDBFile>> PDBFileBuilder::build() { |
| if (Info) { |
| auto ExpectedInfo = Info->build(); |
| if (!ExpectedInfo) |
| return ExpectedInfo.takeError(); |
| File->Info = std::move(*ExpectedInfo); |
| } |
| |
| if (Dbi) { |
| auto ExpectedDbi = Dbi->build(); |
| if (!ExpectedDbi) |
| return ExpectedDbi.takeError(); |
| File->Dbi = std::move(*ExpectedDbi); |
| } |
| |
| if (File->Info && File->Dbi && File->Info->getAge() != File->Dbi->getAge()) |
| return llvm::make_error<RawError>( |
| raw_error_code::corrupt_file, |
| "PDB Stream Age doesn't match Dbi Stream Age!"); |
| |
| return std::move(File); |
| } |