//===- 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 PdbFileBuffer) : File(llvm::make_unique(std::move(PdbFileBuffer))) {} Error PDBFileBuilder::setSuperBlock(const PDBFile::SuperBlock &B) { auto SB = static_cast( File->Allocator.Allocate(sizeof(PDBFile::SuperBlock), llvm::AlignOf::Alignment)); ::memcpy(SB, &B, sizeof(PDBFile::SuperBlock)); return File->setSuperBlock(SB); } void PDBFileBuilder::setStreamSizes(ArrayRef S) { File->StreamSizes = S; } void PDBFileBuilder::setDirectoryBlocks(ArrayRef D) { File->DirectoryBlocks = D; } void PDBFileBuilder::setStreamMap( const std::vector> &S) { File->StreamMap = S; } Error PDBFileBuilder::generateSimpleStreamMap() { if (File->StreamSizes.empty()) return Error::success(); static std::vector> 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 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(*File); return *Info; } DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { if (!Dbi) Dbi = llvm::make_unique(*File); return *Dbi; } Expected> 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( raw_error_code::corrupt_file, "PDB Stream Age doesn't match Dbi Stream Age!"); return std::move(File); }