diff options
Diffstat (limited to 'lib/DebugInfo/MSF/MSFBuilder.cpp')
-rw-r--r-- | lib/DebugInfo/MSF/MSFBuilder.cpp | 116 |
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); +} |