summaryrefslogtreecommitdiff
path: root/lib/DebugInfo/MSF/MSFBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/DebugInfo/MSF/MSFBuilder.cpp')
-rw-r--r--lib/DebugInfo/MSF/MSFBuilder.cpp116
1 files changed, 82 insertions, 34 deletions
diff --git a/lib/DebugInfo/MSF/MSFBuilder.cpp b/lib/DebugInfo/MSF/MSFBuilder.cpp
index 9cd22ab7d887..71609919558a 100644
--- a/lib/DebugInfo/MSF/MSFBuilder.cpp
+++ b/lib/DebugInfo/MSF/MSFBuilder.cpp
@@ -7,11 +7,15 @@
//
//===----------------------------------------------------------------------===//
-#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>
@@ -29,7 +33,7 @@ static const uint32_t kFreePageMap0Block = 1;
static const uint32_t kFreePageMap1Block = 2;
static const uint32_t kNumReservedPages = 3;
-static const uint32_t kDefaultFreePageMap = kFreePageMap0Block;
+static const uint32_t kDefaultFreePageMap = kFreePageMap1Block;
static const uint32_t kDefaultBlockMapAddr = kNumReservedPages;
MSFBuilder::MSFBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow,
@@ -112,11 +116,11 @@ Error MSFBuilder::allocateBlocks(uint32_t NumBlocks,
FreeBlocks.resize(NewBlockCount, true);
// If we crossed over an fpm page, we actually need to allocate 2 extra
// blocks for each FPM group crossed and mark both blocks from the group as
- // used. We may not actually use them since there are many more FPM blocks
- // present than are required to represent all blocks in a given PDB, but we
- // need to make sure they aren't allocated to a stream or something else.
- // At the end when committing the PDB, we'll go through and mark the
- // extraneous ones unused.
+ // used. FPM blocks are marked as allocated regardless of whether or not
+ // they ultimately describe the status of blocks in the file. This means
+ // that not only are extraneous blocks at the end of the main FPM marked as
+ // allocated, but also blocks from the alternate FPM are always marked as
+ // allocated.
while (NextFpmBlock < NewBlockCount) {
NewBlockCount += 2;
FreeBlocks.resize(NewBlockCount, true);
@@ -244,20 +248,7 @@ uint32_t MSFBuilder::computeDirectoryByteSize() const {
return Size;
}
-static void finalizeFpmBlockStatus(uint32_t B, ArrayRef<ulittle32_t> &FpmBlocks,
- BitVector &Fpm) {
- if (FpmBlocks.empty() || FpmBlocks.front() != B) {
- Fpm.set(B);
- return;
- }
-
- // If the next block in the actual layout is this block, it should *not* be
- // free.
- assert(!Fpm.test(B));
- FpmBlocks = FpmBlocks.drop_front();
-}
-
-Expected<MSFLayout> MSFBuilder::build() {
+Expected<MSFLayout> MSFBuilder::generateLayout() {
SuperBlock *SB = Allocator.Allocate<SuperBlock>();
MSFLayout L;
L.SB = SB;
@@ -315,20 +306,77 @@ Expected<MSFLayout> MSFBuilder::build() {
}
}
- // FPM blocks occur in pairs at every `BlockLength` interval. While blocks of
- // this form are reserved for FPM blocks, not all blocks of this form will
- // actually be needed for FPM data because there are more blocks of this form
- // than are required to represent a PDB file with a given number of blocks.
- // So we need to find out which blocks are *actually* going to be real FPM
- // blocks, then mark the reset of the reserved blocks as unallocated.
- MSFStreamLayout FpmLayout = msf::getFpmStreamLayout(L, true);
- auto FpmBlocks = makeArrayRef(FpmLayout.Blocks);
- for (uint32_t B = kFreePageMap0Block; B < SB->NumBlocks;
- B += msf::getFpmIntervalLength(L)) {
- finalizeFpmBlockStatus(B, FpmBlocks, FreeBlocks);
- finalizeFpmBlockStatus(B + 1, FpmBlocks, FreeBlocks);
- }
L.FreePageMap = FreeBlocks;
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);
+}