This is part of the continuing effort to increase parity between LLD and MSVC PDBs. link still doesn't like our PDBs, so the most obvious thing to check was whether adding an empty publics stream would get it to do something else. It still fails in the same way but at least this removes one more variable from the equation. The next logical step would be to try creating an empty globals stream. Differential Revision: https://reviews.llvm.org/D35224 llvm-svn: 307598
222 lines
6.4 KiB
C++
222 lines
6.4 KiB
C++
//===- 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/Native/PDBFileBuilder.h"
|
|
|
|
#include "llvm/ADT/BitVector.h"
|
|
|
|
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
|
|
#include "llvm/DebugInfo/PDB/GenericError.h"
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
|
#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
|
|
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
|
#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
|
|
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
|
|
#include "llvm/DebugInfo/PDB/Native/PublicsStreamBuilder.h"
|
|
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
|
#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
|
|
#include "llvm/Support/BinaryStream.h"
|
|
#include "llvm/Support/BinaryStreamWriter.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::codeview;
|
|
using namespace llvm::msf;
|
|
using namespace llvm::pdb;
|
|
using namespace llvm::support;
|
|
|
|
PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
|
|
: Allocator(Allocator) {}
|
|
|
|
PDBFileBuilder::~PDBFileBuilder() {}
|
|
|
|
Error PDBFileBuilder::initialize(uint32_t BlockSize) {
|
|
auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
|
|
if (!ExpectedMsf)
|
|
return ExpectedMsf.takeError();
|
|
Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
|
|
return Error::success();
|
|
}
|
|
|
|
MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
|
|
|
|
InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
|
|
if (!Info)
|
|
Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
|
|
return *Info;
|
|
}
|
|
|
|
DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
|
|
if (!Dbi)
|
|
Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
|
|
return *Dbi;
|
|
}
|
|
|
|
TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
|
|
if (!Tpi)
|
|
Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
|
|
return *Tpi;
|
|
}
|
|
|
|
TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
|
|
if (!Ipi)
|
|
Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
|
|
return *Ipi;
|
|
}
|
|
|
|
PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
|
|
return Strings;
|
|
}
|
|
|
|
PublicsStreamBuilder &PDBFileBuilder::getPublicsBuilder() {
|
|
if (!Publics)
|
|
Publics = llvm::make_unique<PublicsStreamBuilder>(*Msf);
|
|
return *Publics;
|
|
}
|
|
|
|
Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
|
|
auto ExpectedStream = Msf->addStream(Size);
|
|
if (!ExpectedStream)
|
|
return ExpectedStream.takeError();
|
|
NamedStreams.set(Name, *ExpectedStream);
|
|
return Error::success();
|
|
}
|
|
|
|
Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
|
|
|
|
if (Ipi && Ipi->getRecordCount() > 0) {
|
|
// In theory newer PDBs always have an ID stream, but by saying that we're
|
|
// only going to *really* have an ID stream if there is at least one ID
|
|
// record, we leave open the opportunity to test older PDBs such as those
|
|
// that don't have an ID stream.
|
|
auto &Info = getInfoBuilder();
|
|
Info.addFeature(PdbRaw_FeatureSig::VC140);
|
|
}
|
|
|
|
uint32_t StringsLen = Strings.calculateSerializedSize();
|
|
|
|
if (auto EC = addNamedStream("/names", StringsLen))
|
|
return std::move(EC);
|
|
if (auto EC = addNamedStream("/LinkInfo", 0))
|
|
return std::move(EC);
|
|
|
|
if (Info) {
|
|
if (auto EC = Info->finalizeMsfLayout())
|
|
return std::move(EC);
|
|
}
|
|
if (Dbi) {
|
|
if (auto EC = Dbi->finalizeMsfLayout())
|
|
return std::move(EC);
|
|
}
|
|
if (Tpi) {
|
|
if (auto EC = Tpi->finalizeMsfLayout())
|
|
return std::move(EC);
|
|
}
|
|
if (Ipi) {
|
|
if (auto EC = Ipi->finalizeMsfLayout())
|
|
return std::move(EC);
|
|
}
|
|
if (Publics) {
|
|
if (auto EC = Publics->finalizeMsfLayout())
|
|
return std::move(EC);
|
|
if (Dbi) {
|
|
Dbi->setPublicsStreamIndex(Publics->getStreamIndex());
|
|
Dbi->setSymbolRecordStreamIndex(Publics->getRecordStreamIdx());
|
|
}
|
|
}
|
|
|
|
return Msf->build();
|
|
}
|
|
|
|
Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
|
|
uint32_t SN = 0;
|
|
if (!NamedStreams.get(Name, SN))
|
|
return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
|
|
return SN;
|
|
}
|
|
|
|
Error PDBFileBuilder::commit(StringRef Filename) {
|
|
assert(!Filename.empty());
|
|
auto ExpectedLayout = finalizeMsfLayout();
|
|
if (!ExpectedLayout)
|
|
return ExpectedLayout.takeError();
|
|
auto &Layout = *ExpectedLayout;
|
|
|
|
uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
|
|
auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
|
|
if (OutFileOrError.getError())
|
|
return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path,
|
|
Filename);
|
|
FileBufferByteStream Buffer(std::move(*OutFileOrError),
|
|
llvm::support::little);
|
|
BinaryStreamWriter Writer(Buffer);
|
|
|
|
if (auto EC = Writer.writeObject(*Layout.SB))
|
|
return EC;
|
|
uint32_t BlockMapOffset =
|
|
msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
|
|
Writer.setOffset(BlockMapOffset);
|
|
if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
|
|
return EC;
|
|
|
|
auto DirStream = WritableMappedBlockStream::createDirectoryStream(
|
|
Layout, Buffer, Allocator);
|
|
BinaryStreamWriter DW(*DirStream);
|
|
if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
|
|
return EC;
|
|
|
|
if (auto EC = DW.writeArray(Layout.StreamSizes))
|
|
return EC;
|
|
|
|
for (const auto &Blocks : Layout.StreamMap) {
|
|
if (auto EC = DW.writeArray(Blocks))
|
|
return EC;
|
|
}
|
|
|
|
auto ExpectedSN = getNamedStreamIndex("/names");
|
|
if (!ExpectedSN)
|
|
return ExpectedSN.takeError();
|
|
|
|
auto NS = WritableMappedBlockStream::createIndexedStream(
|
|
Layout, Buffer, *ExpectedSN, Allocator);
|
|
BinaryStreamWriter NSWriter(*NS);
|
|
if (auto EC = Strings.commit(NSWriter))
|
|
return EC;
|
|
|
|
if (Info) {
|
|
if (auto EC = Info->commit(Layout, Buffer))
|
|
return EC;
|
|
}
|
|
|
|
if (Dbi) {
|
|
if (auto EC = Dbi->commit(Layout, Buffer))
|
|
return EC;
|
|
}
|
|
|
|
if (Tpi) {
|
|
if (auto EC = Tpi->commit(Layout, Buffer))
|
|
return EC;
|
|
}
|
|
|
|
if (Ipi) {
|
|
if (auto EC = Ipi->commit(Layout, Buffer))
|
|
return EC;
|
|
}
|
|
|
|
if (Publics) {
|
|
auto PS = WritableMappedBlockStream::createIndexedStream(
|
|
Layout, Buffer, Publics->getStreamIndex(), Allocator);
|
|
BinaryStreamWriter PSWriter(*PS);
|
|
if (auto EC = Publics->commit(PSWriter))
|
|
return EC;
|
|
}
|
|
|
|
return Buffer.commit();
|
|
}
|