You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
4.1 KiB
128 lines
4.1 KiB
4 months ago
|
//===- 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);
|
||
|
}
|