#include <vector>
namespace llvm {
+class FileBufferByteStream;
+class WritableBinaryStream;
namespace msf {
class MSFBuilder {
/// Finalize the layout and build the headers and structures that describe the
/// MSF layout and can be written directly to the MSF file.
- Expected<MSFLayout> build();
+ Expected<MSFLayout> generateLayout();
+
+ /// Write the MSF layout to the underlying file.
+ Expected<FileBufferByteStream> commit(StringRef Path, MSFLayout &Layout);
BumpPtrAllocator &getAllocator() { return Allocator; }
std::unique_ptr<MemoryBuffer> Content;
};
- Expected<msf::MSFLayout> finalizeMsfLayout();
+ Error finalizeMsfLayout();
Expected<uint32_t> allocateNamedStream(StringRef Name, uint32_t Size);
void commitFpm(WritableBinaryStream &MsfBuffer, const msf::MSFLayout &Layout);
return Error::success();
}
+ /// Returns a pointer to the start of the buffer.
+ uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
+
+ /// Returns a pointer to the end of the buffer.
+ uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
+
private:
std::unique_ptr<FileOutputBuffer> FileBuffer;
};
Error commit() override { return Impl.commit(); }
+ /// Returns a pointer to the start of the buffer.
+ uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
+
+ /// Returns a pointer to the end of the buffer.
+ uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
+
private:
StreamImpl Impl;
};
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/DebugInfo/MSF/MSFError.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
return Size;
}
-Expected<MSFLayout> MSFBuilder::build() {
+Expected<MSFLayout> MSFBuilder::generateLayout() {
SuperBlock *SB = Allocator.Allocate<SuperBlock>();
MSFLayout L;
L.SB = SB;
return L;
}
+
+static void commitFpm(WritableBinaryStream &MsfBuffer, const MSFLayout &Layout,
+ BumpPtrAllocator &Allocator) {
+ auto FpmStream =
+ WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
+
+ // We only need to create the alt fpm stream so that it gets initialized.
+ WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
+ true);
+
+ uint32_t BI = 0;
+ BinaryStreamWriter FpmWriter(*FpmStream);
+ while (BI < Layout.SB->NumBlocks) {
+ uint8_t ThisByte = 0;
+ for (uint32_t I = 0; I < 8; ++I) {
+ bool IsFree =
+ (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
+ uint8_t Mask = uint8_t(IsFree) << I;
+ ThisByte |= Mask;
+ ++BI;
+ }
+ cantFail(FpmWriter.writeObject(ThisByte));
+ }
+ assert(FpmWriter.bytesRemaining() == 0);
+}
+
+Expected<FileBufferByteStream> MSFBuilder::commit(StringRef Path,
+ MSFLayout &Layout) {
+ Expected<MSFLayout> L = generateLayout();
+ if (!L)
+ return L.takeError();
+
+ Layout = std::move(*L);
+
+ uint64_t FileSize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
+ auto OutFileOrError = FileOutputBuffer::create(Path, FileSize);
+ if (auto EC = OutFileOrError.takeError())
+ return std::move(EC);
+
+ FileBufferByteStream Buffer(std::move(*OutFileOrError),
+ llvm::support::little);
+ BinaryStreamWriter Writer(Buffer);
+
+ if (auto EC = Writer.writeObject(*Layout.SB))
+ return std::move(EC);
+
+ commitFpm(Buffer, Layout, Allocator);
+
+ uint32_t BlockMapOffset =
+ msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
+ Writer.setOffset(BlockMapOffset);
+ if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
+ return std::move(EC);
+
+ auto DirStream = WritableMappedBlockStream::createDirectoryStream(
+ Layout, Buffer, Allocator);
+ BinaryStreamWriter DW(*DirStream);
+ if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
+ return std::move(EC);
+
+ if (auto EC = DW.writeArray(Layout.StreamSizes))
+ return std::move(EC);
+
+ for (const auto &Blocks : Layout.StreamMap) {
+ if (auto EC = DW.writeArray(Blocks))
+ return std::move(EC);
+ }
+
+ return std::move(Buffer);
+}
InjectedSources.push_back(std::move(Desc));
}
-Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
+Error PDBFileBuilder::finalizeMsfLayout() {
if (Ipi && Ipi->getRecordCount() > 0) {
// In theory newer PDBs always have an ID stream, but by saying that we're
if (Gsi) {
if (auto EC = Gsi->finalizeMsfLayout())
- return std::move(EC);
+ return EC;
if (Dbi) {
Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
}
if (Tpi) {
if (auto EC = Tpi->finalizeMsfLayout())
- return std::move(EC);
+ return EC;
}
if (Dbi) {
if (auto EC = Dbi->finalizeMsfLayout())
- return std::move(EC);
+ return EC;
}
SN = allocateNamedStream("/names", StringsLen);
if (!SN)
if (Ipi) {
if (auto EC = Ipi->finalizeMsfLayout())
- return std::move(EC);
+ return EC;
}
// Do this last, since it relies on the named stream map being complete, and
// that can be updated by previous steps in the finalization.
if (Info) {
if (auto EC = Info->finalizeMsfLayout())
- return std::move(EC);
+ return EC;
}
if (!InjectedSources.empty()) {
// that can be updated by previous steps in the finalization.
if (Info) {
if (auto EC = Info->finalizeMsfLayout())
- return std::move(EC);
+ return EC;
}
- return Msf->build();
+ return Error::success();
}
Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
return SN;
}
-void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
- const MSFLayout &Layout) {
- auto FpmStream =
- WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
-
- // We only need to create the alt fpm stream so that it gets initialized.
- WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
- true);
-
- uint32_t BI = 0;
- BinaryStreamWriter FpmWriter(*FpmStream);
- while (BI < Layout.SB->NumBlocks) {
- uint8_t ThisByte = 0;
- for (uint32_t I = 0; I < 8; ++I) {
- bool IsFree =
- (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
- uint8_t Mask = uint8_t(IsFree) << I;
- ThisByte |= Mask;
- ++BI;
- }
- cantFail(FpmWriter.writeObject(ThisByte));
- }
- assert(FpmWriter.bytesRemaining() == 0);
-}
-
void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
const msf::MSFLayout &Layout) {
assert(!InjectedSourceTable.empty());
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 (auto E = OutFileOrError.takeError())
- return E;
- FileOutputBuffer *FOB = OutFileOrError->get();
-
- FileBufferByteStream Buffer(std::move(*OutFileOrError),
- llvm::support::little);
- BinaryStreamWriter Writer(Buffer);
-
- if (auto EC = Writer.writeObject(*Layout.SB))
- return EC;
-
- commitFpm(Buffer, Layout);
-
- 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))
+ if (auto EC = finalizeMsfLayout())
return EC;
- for (const auto &Blocks : Layout.StreamMap) {
- if (auto EC = DW.writeArray(Blocks))
- return EC;
- }
+ MSFLayout Layout;
+ auto ExpectedMsfBuffer = Msf->commit(Filename, Layout);
+ if (!ExpectedMsfBuffer)
+ return ExpectedMsfBuffer.takeError();
+ FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
auto ExpectedSN = getNamedStreamIndex("/names");
if (!ExpectedSN)
uint64_t InfoStreamFileOffset =
blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
- FOB->getBufferStart() + InfoStreamFileOffset);
+ Buffer.getBufferStart() + InfoStreamFileOffset);
commitInjectedSources(Buffer, Layout);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
- auto ExpectedL1 = Msf.build();
+ auto ExpectedL1 = Msf.generateLayout();
EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
MSFLayout &L1 = *ExpectedL1;
auto Blocks = Msf2.getStreamBlocks(0);
EXPECT_EQ(1U, Blocks.size());
- auto ExpectedL2 = Msf2.build();
+ auto ExpectedL2 = Msf2.generateLayout();
EXPECT_THAT_EXPECTED(ExpectedL2, Succeeded());
MSFLayout &L2 = *ExpectedL2;
auto NewDirBlocks = L2.DirectoryBlocks;
EXPECT_THAT_EXPECTED(Msf.addStream(4096 * 4096 / sizeof(uint32_t)),
Succeeded());
- auto ExpectedL1 = Msf.build();
+ auto ExpectedL1 = Msf.generateLayout();
EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
MSFLayout &L1 = *ExpectedL1;
auto DirBlocks = L1.DirectoryBlocks;
}
++ExpectedNumBlocks; // The directory itself should use 1 block
- auto ExpectedLayout = Msf.build();
+ auto ExpectedLayout = Msf.generateLayout();
EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(4096U, L.SB->BlockSize);
EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());
EXPECT_THAT_EXPECTED(Msf.addStream(2048, {B + 2}), Succeeded());
- auto ExpectedLayout = Msf.build();
+ auto ExpectedLayout = Msf.generateLayout();
EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);
uint32_t Size = 4096 * 4096 / 4;
EXPECT_THAT_EXPECTED(Msf.addStream(Size), Succeeded());
- auto ExpectedLayout = Msf.build();
+ auto ExpectedLayout = Msf.generateLayout();
EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(2U, L.DirectoryBlocks.size());
ASSERT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
- auto ExpectedLayout = Msf.build();
+ auto ExpectedLayout = Msf.generateLayout();
ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(1U, L.DirectoryBlocks.size());
Expected<uint32_t> SN = Msf.addStream(StreamSize);
ASSERT_THAT_EXPECTED(SN, Succeeded());
- auto ExpectedLayout = Msf.build();
+ auto ExpectedLayout = Msf.generateLayout();
ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
auto BlocksRef = L.StreamMap[*SN];