[llvm] r275611 - [pdb] Introduce MsfBuilder for laying out PDB files.
Eric Christopher via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 15 14:26:35 PDT 2016
I guess we don't capitalize coff... *shrug*
-eric
On Fri, Jul 15, 2016 at 2:25 PM Zachary Turner <zturner at google.com> wrote:
> Maybe. We capitalize PDB, but looking back on it I think it's painful on
> the eyes seeing so many capital letters back to back, and I wish Pdb had
> not been capitalized. I don't know though, I don't feel super strongly
>
> On Fri, Jul 15, 2016 at 2:21 PM Eric Christopher <echristo at gmail.com>
> wrote:
>
>> Seems like a silly nit, but should we just capitalize MSF since the
>> format is capitalized?
>>
>> -eric
>>
>> On Fri, Jul 15, 2016 at 1:51 PM Zachary Turner via llvm-commits <
>> llvm-commits at lists.llvm.org> wrote:
>>
>>> Author: zturner
>>> Date: Fri Jul 15 15:43:38 2016
>>> New Revision: 275611
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=275611&view=rev
>>> Log:
>>> [pdb] Introduce MsfBuilder for laying out PDB files.
>>>
>>> Reviewed by: ruiu
>>> Differential Revision: https://reviews.llvm.org/D22308
>>>
>>> Added:
>>> llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h
>>> llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h
>>> llvm/trunk/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp
>>> llvm/trunk/lib/DebugInfo/PDB/Raw/MsfCommon.cpp
>>> llvm/trunk/unittests/DebugInfo/PDB/ErrorChecking.h
>>> llvm/trunk/unittests/DebugInfo/PDB/MsfBuilderTest.cpp
>>> Modified:
>>> llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt
>>> llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt
>>> llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
>>>
>>> Added: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h?rev=275611&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h (added)
>>> +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfBuilder.h Fri Jul 15
>>> 15:43:38 2016
>>> @@ -0,0 +1,136 @@
>>> +//===- MSFBuilder.h - MSF Directory & Metadata Builder ----------*- C++
>>> -*-===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>>
>>> +//===----------------------------------------------------------------------===//
>>> +
>>> +#ifndef LLVM_DEBUGINFO_PDB_RAW_MSFBUILDER_H
>>> +#define LLVM_DEBUGINFO_PDB_RAW_MSFBUILDER_H
>>> +
>>> +#include "llvm/ADT/ArrayRef.h"
>>> +#include "llvm/ADT/BitVector.h"
>>> +
>>> +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h"
>>> +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
>>> +
>>> +#include "llvm/Support/Allocator.h"
>>> +#include "llvm/Support/Endian.h"
>>> +#include "llvm/Support/Error.h"
>>> +
>>> +#include <utility>
>>> +#include <vector>
>>> +
>>> +namespace llvm {
>>> +namespace pdb {
>>> +class MsfBuilder {
>>> +public:
>>> + /// \brief Create a new `MsfBuilder`.
>>> + ///
>>> + /// \param BlockSize The internal block size used by the PDB file.
>>> See
>>> + /// isValidBlockSize() for a list of valid block sizes.
>>> + ///
>>> + /// \param MinBlockCount Causes the builder to reserve up front space
>>> for
>>> + /// at least `MinBlockCount` blocks. This is useful when using
>>> `MsfBuilder`
>>> + /// to read an existing PDB that you want to write back out later.
>>> The
>>> + /// original PDB file's SuperBlock contains the exact number of
>>> blocks used
>>> + /// by the file, so is a good hint as to how many blocks the new PDB
>>> file
>>> + /// will contain. Furthermore, it is actually necessary in this
>>> case. To
>>> + /// preserve stability of the file's layout, it is helpful to try to
>>> keep
>>> + /// all streams mapped to their original block numbers. To ensure
>>> that this
>>> + /// is possible, space for all blocks must be allocated beforehand so
>>> that
>>> + /// streams can be assigned to them.
>>> + ///
>>> + /// \param CanGrow If true, any operation which results in an attempt
>>> to
>>> + /// locate a free block when all available blocks have been exhausted
>>> will
>>> + /// allocate a new block, thereby growing the size of the final PDB
>>> file.
>>> + /// When false, any such attempt will result in an error. This is
>>> especially
>>> + /// useful in testing scenarios when you know your test isn't going
>>> to do
>>> + /// anything to increase the size of the file, so having an Error
>>> returned if
>>> + /// it were to happen would catch a programming error
>>> + ///
>>> + /// \returns an llvm::Error representing whether the operation
>>> succeeded or
>>> + /// failed. Currently the only way this can fail is if an invalid
>>> block size
>>> + /// is specified, or `MinBlockCount` does not leave enough room for
>>> the
>>> + /// mandatory reserved blocks required by an MSF file.
>>> + static Expected<MsfBuilder> create(BumpPtrAllocator &Allocator,
>>> + uint32_t BlockSize,
>>> + uint32_t MinBlockCount = 0,
>>> + bool CanGrow = true);
>>> +
>>> + /// Request the block map to be at a specific block address. This is
>>> useful
>>> + /// when editing a PDB and you want the layout to be as stable as
>>> possible.
>>> + Error setBlockMapAddr(uint32_t Addr);
>>> +
>>> + /// Add a stream to the MSF file with the given size, occupying the
>>> given
>>> + /// list of blocks. This is useful when reading a PDB file and you
>>> want a
>>> + /// particular stream to occupy the original set of blocks. If the
>>> given
>>> + /// blocks are already allocated, or if the number of blocks
>>> specified is
>>> + /// incorrect for the given stream size, this function will return an
>>> Error.
>>> + Error addStream(uint32_t Size, ArrayRef<uint32_t> Blocks);
>>> +
>>> + /// Add a stream to the MSF file with the given size, occupying any
>>> available
>>> + /// blocks that the builder decides to use. This is useful when
>>> building a
>>> + /// new PDB file from scratch and you don't care what blocks a stream
>>> occupies
>>> + /// but you just want it to work.
>>> + Error addStream(uint32_t Size);
>>> +
>>> + /// Update the size of an existing stream. This will allocate or
>>> deallocate
>>> + /// blocks as needed to match the requested size. This can fail if
>>> `CanGrow`
>>> + /// was set to false when initializing the `MsfBuilder`.
>>> + Error setStreamSize(uint32_t Idx, uint32_t Size);
>>> +
>>> + /// Get the total number of streams in the MSF layout. This should
>>> return 1
>>> + /// for every call to `addStream`.
>>> + uint32_t getNumStreams() const;
>>> +
>>> + /// Get the size of a stream by index.
>>> + uint32_t getStreamSize(uint32_t StreamIdx) const;
>>> +
>>> + /// Get the list of blocks allocated to a particular stream.
>>> + ArrayRef<uint32_t> getStreamBlocks(uint32_t StreamIdx) const;
>>> +
>>> + /// Get the total number of blocks that will be allocated to actual
>>> data in
>>> + /// this MSF file.
>>> + uint32_t getNumUsedBlocks() const;
>>> +
>>> + /// Get the total number of blocks that exist in the MSF file but are
>>> not
>>> + /// allocated to any valid data.
>>> + uint32_t getNumFreeBlocks() const;
>>> +
>>> + /// Get the total number of blocks in the MSF file. In practice this
>>> is equal
>>> + /// to `getNumUsedBlocks() + getNumFreeBlocks()`.
>>> + uint32_t getTotalBlockCount() const;
>>> +
>>> + /// Check whether a particular block is allocated or free.
>>> + bool isBlockFree(uint32_t Idx) const;
>>> +
>>> + /// Finalize the layout and build the headers and structures that
>>> describe the
>>> + /// MSF layout and can be written directly to the MSF file.
>>> + Expected<msf::Layout> build();
>>> +
>>> +private:
>>> + MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow,
>>> + BumpPtrAllocator &Allocator);
>>> +
>>> + Error allocateBlocks(uint32_t NumBlocks, MutableArrayRef<uint32_t>
>>> Blocks);
>>> + uint32_t computeDirectoryByteSize() const;
>>> +
>>> + typedef std::vector<uint32_t> BlockList;
>>> +
>>> + BumpPtrAllocator &Allocator;
>>> +
>>> + bool IsGrowable;
>>> + uint32_t BlockSize;
>>> + uint32_t MininumBlocks;
>>> + uint32_t BlockMapAddr;
>>> + BitVector FreeBlocks;
>>> + std::vector<uint32_t> DirectoryBlocks;
>>> + std::vector<std::pair<uint32_t, BlockList>> StreamData;
>>> +};
>>> +}
>>> +}
>>> +
>>> +#endif
>>>
>>> Added: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h?rev=275611&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h (added)
>>> +++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/MsfCommon.h Fri Jul 15
>>> 15:43:38 2016
>>> @@ -0,0 +1,83 @@
>>> +//===- MsfCommon.h - Common types and functions for MSF files ---*- C++
>>> -*-===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>>
>>> +//===----------------------------------------------------------------------===//
>>> +
>>> +#ifndef LLVM_DEBUGINFO_PDB_RAW_MSFCOMMON_H
>>> +#define LLVM_DEBUGINFO_PDB_RAW_MSFCOMMON_H
>>> +
>>> +#include "llvm/ADT/ArrayRef.h"
>>> +
>>> +#include "llvm/Support/Endian.h"
>>> +#include "llvm/Support/Error.h"
>>> +#include "llvm/Support/MathExtras.h"
>>> +
>>> +#include <vector>
>>> +
>>> +namespace llvm {
>>> +namespace pdb {
>>> +namespace msf {
>>> +static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o',
>>> 'f',
>>> + 't', ' ', 'C', '/', 'C', '+', '+',
>>> ' ',
>>> + 'M', 'S', 'F', ' ', '7', '.', '0',
>>> '0',
>>> + '\r', '\n', '\x1a', 'D', 'S', '\0', '\0',
>>> '\0'};
>>> +
>>> +// The superblock is overlaid at the beginning of the file (offset 0).
>>> +// It starts with a magic header and is followed by information which
>>> +// describes the layout of the file system.
>>> +struct SuperBlock {
>>> + char MagicBytes[sizeof(Magic)];
>>> + // The file system is split into a variable number of fixed size
>>> elements.
>>> + // These elements are referred to as blocks. The size of a block may
>>> vary
>>> + // from system to system.
>>> + support::ulittle32_t BlockSize;
>>> + // This field's purpose is not yet known.
>>> + support::ulittle32_t Unknown0;
>>> + // This contains the number of blocks resident in the file system. In
>>> + // practice, NumBlocks * BlockSize is equivalent to the size of the
>>> PDB
>>> + // file.
>>> + support::ulittle32_t NumBlocks;
>>> + // This contains the number of bytes which make up the directory.
>>> + support::ulittle32_t NumDirectoryBytes;
>>> + // This field's purpose is not yet known.
>>> + support::ulittle32_t Unknown1;
>>> + // This contains the block # of the block map.
>>> + support::ulittle32_t BlockMapAddr;
>>> +};
>>> +
>>> +struct Layout {
>>> + SuperBlock *SB;
>>> + ArrayRef<support::ulittle32_t> DirectoryBlocks;
>>> + ArrayRef<support::ulittle32_t> StreamSizes;
>>> + std::vector<ArrayRef<support::ulittle32_t>> StreamMap;
>>> +};
>>> +
>>> +inline bool isValidBlockSize(uint32_t Size) {
>>> + switch (Size) {
>>> + case 512:
>>> + case 1024:
>>> + case 2048:
>>> + case 4096:
>>> + return true;
>>> + }
>>> + return false;
>>> +}
>>> +
>>> +inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
>>> + return alignTo(NumBytes, BlockSize) / BlockSize;
>>> +}
>>> +
>>> +inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize)
>>> {
>>> + return BlockNumber * BlockSize;
>>> +}
>>> +
>>> +Error validateSuperBlock(const SuperBlock &SB);
>>> +}
>>> +}
>>> +}
>>> +
>>> +#endif
>>>
>>> Modified: llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt?rev=275611&r1=275610&r2=275611&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt (original)
>>> +++ llvm/trunk/lib/DebugInfo/PDB/CMakeLists.txt Fri Jul 15 15:43:38 2016
>>> @@ -38,6 +38,8 @@ add_pdb_impl_folder(Raw
>>> Raw/MappedBlockStream.cpp
>>> Raw/ModInfo.cpp
>>> Raw/ModStream.cpp
>>> + Raw/MsfBuilder.cpp
>>> + Raw/MsfCommon.cpp
>>> Raw/NameHashTable.cpp
>>> Raw/NameMap.cpp
>>> Raw/PDBFile.cpp
>>>
>>> Added: llvm/trunk/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp?rev=275611&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp (added)
>>> +++ llvm/trunk/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp Fri Jul 15 15:43:38
>>> 2016
>>> @@ -0,0 +1,240 @@
>>> +//===- MSFBuilder.cpp - MSF Directory & Metadata Builder --------*- 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/MsfBuilder.h"
>>> +#include "llvm/DebugInfo/PDB/Raw/RawError.h"
>>> +
>>> +using namespace llvm;
>>> +using namespace llvm::pdb;
>>> +using namespace llvm::pdb::msf;
>>> +using namespace llvm::support;
>>> +
>>> +namespace {
>>> +const uint32_t kSuperBlockBlock = 0;
>>> +const uint32_t kDefaultBlockMapAddr = 1;
>>> +}
>>> +
>>> +MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool
>>> CanGrow,
>>> + BumpPtrAllocator &Allocator)
>>> + : Allocator(Allocator), BlockSize(BlockSize),
>>> MininumBlocks(MinBlockCount),
>>> + IsGrowable(CanGrow), BlockMapAddr(kDefaultBlockMapAddr),
>>> + FreeBlocks(MinBlockCount + 2U, true) {
>>> + FreeBlocks[kSuperBlockBlock] = false;
>>> + FreeBlocks[BlockMapAddr] = false;
>>> +}
>>> +
>>> +Expected<MsfBuilder> MsfBuilder::create(BumpPtrAllocator &Allocator,
>>> + uint32_t BlockSize,
>>> + uint32_t MinBlockCount, bool
>>> CanGrow) {
>>> + if (!msf::isValidBlockSize(BlockSize))
>>> + return make_error<RawError>(raw_error_code::unspecified,
>>> + "The requested block size is
>>> unsupported");
>>> +
>>> + return MsfBuilder(BlockSize, MinBlockCount, CanGrow, Allocator);
>>> +}
>>> +
>>> +Error MsfBuilder::setBlockMapAddr(uint32_t Addr) {
>>> + if (Addr == BlockMapAddr)
>>> + return Error::success();
>>> +
>>> + if (Addr >= FreeBlocks.size()) {
>>> + if (!IsGrowable)
>>> + return make_error<RawError>(raw_error_code::unspecified,
>>> + "Cannot grow the number of blocks");
>>> + FreeBlocks.resize(Addr + 1);
>>> + }
>>> +
>>> + if (!isBlockFree(Addr))
>>> + return make_error<RawError>(raw_error_code::unspecified,
>>> + "Attempt to reuse an allocated block");
>>> + FreeBlocks[BlockMapAddr] = true;
>>> + FreeBlocks[Addr] = false;
>>> + BlockMapAddr = Addr;
>>> + return Error::success();
>>> +}
>>> +
>>> +Error MsfBuilder::allocateBlocks(uint32_t NumBlocks,
>>> + MutableArrayRef<uint32_t> Blocks) {
>>> + if (NumBlocks == 0)
>>> + return Error::success();
>>> +
>>> + uint32_t NumFreeBlocks = FreeBlocks.count();
>>> + if (NumFreeBlocks < NumBlocks) {
>>> + if (!IsGrowable)
>>> + return make_error<RawError>(raw_error_code::unspecified,
>>> + "There are no free Blocks in the
>>> file");
>>> + uint32_t AllocBlocks = NumBlocks - NumFreeBlocks;
>>> + FreeBlocks.resize(AllocBlocks + FreeBlocks.size(), true);
>>> + }
>>> +
>>> + int I = 0;
>>> + int Block = FreeBlocks.find_first();
>>> + do {
>>> + assert(Block != -1 && "We ran out of Blocks!");
>>> +
>>> + uint32_t NextBlock = static_cast<uint32_t>(Block);
>>> + Blocks[I++] = NextBlock;
>>> + FreeBlocks.reset(NextBlock);
>>> + Block = FreeBlocks.find_next(Block);
>>> + } while (--NumBlocks > 0);
>>> + return Error::success();
>>> +}
>>> +
>>> +uint32_t MsfBuilder::getNumUsedBlocks() const {
>>> + return getTotalBlockCount() - getNumFreeBlocks();
>>> +}
>>> +
>>> +uint32_t MsfBuilder::getNumFreeBlocks() const { return
>>> FreeBlocks.count(); }
>>> +
>>> +uint32_t MsfBuilder::getTotalBlockCount() const { return
>>> FreeBlocks.size(); }
>>> +
>>> +bool MsfBuilder::isBlockFree(uint32_t Idx) const { return
>>> FreeBlocks[Idx]; }
>>> +
>>> +Error MsfBuilder::addStream(uint32_t Size, ArrayRef<uint32_t> Blocks) {
>>> + // Add a new stream mapped to the specified blocks. Verify that the
>>> specified
>>> + // blocks are both necessary and sufficient for holding the requested
>>> number
>>> + // of bytes, and verify that all requested blocks are free.
>>> + uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
>>> + if (ReqBlocks != Blocks.size())
>>> + return make_error<RawError>(
>>> + raw_error_code::unspecified,
>>> + "Incorrect number of blocks for requested stream size");
>>> + for (auto Block : Blocks) {
>>> + if (Block >= FreeBlocks.size())
>>> + FreeBlocks.resize(Block + 1, true);
>>> +
>>> + if (!FreeBlocks.test(Block))
>>> + return make_error<RawError>(
>>> + raw_error_code::unspecified,
>>> + "Attempt to re-use an already allocated block");
>>> + }
>>> + // Mark all the blocks occupied by the new stream as not free.
>>> + for (auto Block : Blocks) {
>>> + FreeBlocks.reset(Block);
>>> + }
>>> + StreamData.push_back(std::make_pair(Size, Blocks));
>>> + return Error::success();
>>> +}
>>> +
>>> +Error MsfBuilder::addStream(uint32_t Size) {
>>> + uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
>>> + std::vector<uint32_t> NewBlocks;
>>> + NewBlocks.resize(ReqBlocks);
>>> + if (auto EC = allocateBlocks(ReqBlocks, NewBlocks))
>>> + return EC;
>>> + StreamData.push_back(std::make_pair(Size, NewBlocks));
>>> + return Error::success();
>>> +}
>>> +
>>> +Error MsfBuilder::setStreamSize(uint32_t Idx, uint32_t Size) {
>>> + uint32_t OldSize = getStreamSize(Idx);
>>> + if (OldSize == Size)
>>> + return Error::success();
>>> +
>>> + uint32_t NewBlocks = bytesToBlocks(Size, BlockSize);
>>> + uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize);
>>> +
>>> + if (NewBlocks > OldBlocks) {
>>> + uint32_t AddedBlocks = NewBlocks - OldBlocks;
>>> + // If we're growing, we have to allocate new Blocks.
>>> + std::vector<uint32_t> AddedBlockList;
>>> + AddedBlockList.resize(AddedBlocks);
>>> + if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList))
>>> + return EC;
>>> + auto &CurrentBlocks = StreamData[Idx].second;
>>> + CurrentBlocks.insert(CurrentBlocks.end(), AddedBlockList.begin(),
>>> + AddedBlockList.end());
>>> + } else if (OldBlocks > NewBlocks) {
>>> + // For shrinking, free all the Blocks in the Block map, update the
>>> stream
>>> + // data, then shrink the directory.
>>> + uint32_t RemovedBlocks = OldBlocks - NewBlocks;
>>> + auto CurrentBlocks = ArrayRef<uint32_t>(StreamData[Idx].second);
>>> + auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks);
>>> + for (auto P : RemovedBlockList)
>>> + FreeBlocks[P] = true;
>>> + StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks);
>>> + }
>>> +
>>> + StreamData[Idx].first = Size;
>>> + return Error::success();
>>> +}
>>> +
>>> +uint32_t MsfBuilder::getNumStreams() const { return StreamData.size(); }
>>> +
>>> +uint32_t MsfBuilder::getStreamSize(uint32_t StreamIdx) const {
>>> + return StreamData[StreamIdx].first;
>>> +}
>>> +
>>> +ArrayRef<uint32_t> MsfBuilder::getStreamBlocks(uint32_t StreamIdx)
>>> const {
>>> + return StreamData[StreamIdx].second;
>>> +}
>>> +
>>> +uint32_t MsfBuilder::computeDirectoryByteSize() const {
>>> + // The directory has the following layout, where each item is a
>>> ulittle32_t:
>>> + // NumStreams
>>> + // StreamSizes[NumStreams]
>>> + // StreamBlocks[NumStreams][]
>>> + uint32_t Size = sizeof(ulittle32_t); // NumStreams
>>> + Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes
>>> + for (const auto &D : StreamData) {
>>> + uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize);
>>> + assert(ExpectedNumBlocks == D.second.size() &&
>>> + "Unexpected number of blocks");
>>> + Size += ExpectedNumBlocks * sizeof(ulittle32_t);
>>> + }
>>> + return Size;
>>> +}
>>> +
>>> +Expected<Layout> MsfBuilder::build() {
>>> + Layout L;
>>> + L.SB = Allocator.Allocate<SuperBlock>();
>>> + std::memcpy(L.SB->MagicBytes, Magic, sizeof(Magic));
>>> + L.SB->BlockMapAddr = BlockMapAddr;
>>> + L.SB->BlockSize = BlockSize;
>>> + L.SB->NumDirectoryBytes = computeDirectoryByteSize();
>>> + L.SB->Unknown0 = 0;
>>> + L.SB->Unknown1 = 0;
>>> +
>>> + uint32_t NumDirectoryBlocks =
>>> + bytesToBlocks(L.SB->NumDirectoryBytes, BlockSize);
>>> + // The directory blocks should be re-allocated as a stable pointer.
>>> + std::vector<uint32_t> DirectoryBlocks;
>>> + DirectoryBlocks.resize(NumDirectoryBlocks);
>>> + if (auto EC = allocateBlocks(NumDirectoryBlocks, DirectoryBlocks))
>>> + return std::move(EC);
>>> +
>>> + // Don't set the number of blocks in the file until after allocating
>>> Blocks
>>> + // for
>>> + // the directory, since the allocation might cause the file to need
>>> to grow.
>>> + L.SB->NumBlocks = FreeBlocks.size();
>>> +
>>> + ulittle32_t *DirBlocks =
>>> Allocator.Allocate<ulittle32_t>(NumDirectoryBlocks);
>>> + std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks,
>>> + DirBlocks);
>>> + L.DirectoryBlocks = ArrayRef<ulittle32_t>(DirBlocks,
>>> NumDirectoryBlocks);
>>> +
>>> + // The stream sizes should be re-allocated as a stable pointer and
>>> the stream
>>> + // map should have each of its entries allocated as a separate stable
>>> pointer.
>>> + if (StreamData.size() > 0) {
>>> + ulittle32_t *Sizes =
>>> Allocator.Allocate<ulittle32_t>(StreamData.size());
>>> + L.StreamSizes = ArrayRef<ulittle32_t>(Sizes, StreamData.size());
>>> + L.StreamMap.resize(StreamData.size());
>>> + for (uint32_t I = 0; I < StreamData.size(); ++I) {
>>> + Sizes[I] = StreamData[I].first;
>>> + ulittle32_t *BlockList =
>>> + Allocator.Allocate<ulittle32_t>(StreamData[I].second.size());
>>> + std::uninitialized_copy_n(StreamData[I].second.begin(),
>>> + StreamData[I].second.size(), BlockList);
>>> + L.StreamMap[I] =
>>> + ArrayRef<ulittle32_t>(BlockList, StreamData[I].second.size());
>>> + }
>>> + }
>>> +
>>> + return L;
>>> +}
>>>
>>> Added: llvm/trunk/lib/DebugInfo/PDB/Raw/MsfCommon.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/MsfCommon.cpp?rev=275611&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/lib/DebugInfo/PDB/Raw/MsfCommon.cpp (added)
>>> +++ llvm/trunk/lib/DebugInfo/PDB/Raw/MsfCommon.cpp Fri Jul 15 15:43:38
>>> 2016
>>> @@ -0,0 +1,48 @@
>>> +//===- MsfCommon.cpp - Common types and functions for MSF files -*- 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/MsfCommon.h"
>>> +#include "llvm/DebugInfo/PDB/Raw/RawError.h"
>>> +
>>> +using namespace llvm;
>>> +using namespace llvm::pdb::msf;
>>> +
>>> +Error llvm::pdb::msf::validateSuperBlock(const SuperBlock &SB) {
>>> + // Check the magic bytes.
>>> + if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0)
>>> + return make_error<RawError>(raw_error_code::corrupt_file,
>>> + "MSF magic header doesn't match");
>>> +
>>> + if (!isValidBlockSize(SB.BlockSize))
>>> + return make_error<RawError>(raw_error_code::corrupt_file,
>>> + "Unsupported block size.");
>>> +
>>> + // We don't support directories whose sizes aren't a multiple of four
>>> bytes.
>>> + if (SB.NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
>>> + return make_error<RawError>(raw_error_code::corrupt_file,
>>> + "Directory size is not multiple of 4.");
>>> +
>>> + // The number of blocks which comprise the directory is a simple
>>> function of
>>> + // the number of bytes it contains.
>>> + uint64_t NumDirectoryBlocks =
>>> + bytesToBlocks(SB.NumDirectoryBytes, SB.BlockSize);
>>> +
>>> + // The directory, as we understand it, is a block which consists of a
>>> list of
>>> + // block numbers. It is unclear what would happen if the number of
>>> blocks
>>> + // couldn't fit on a single block.
>>> + if (NumDirectoryBlocks > SB.BlockSize / sizeof(support::ulittle32_t))
>>> + return make_error<RawError>(raw_error_code::corrupt_file,
>>> + "Too many directory blocks.");
>>> +
>>> + if (SB.BlockMapAddr == 0)
>>> + return make_error<RawError>(raw_error_code::corrupt_file,
>>> + "Block 0 is reserved");
>>> +
>>> + return Error::success();
>>> +}
>>>
>>> Modified: llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt?rev=275611&r1=275610&r2=275611&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt (original)
>>> +++ llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt Fri Jul 15
>>> 15:43:38 2016
>>> @@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
>>>
>>> set(DebugInfoPDBSources
>>> MappedBlockStreamTest.cpp
>>> + MsfBuilderTest.cpp
>>> PDBApiTest.cpp
>>> )
>>>
>>>
>>> Added: llvm/trunk/unittests/DebugInfo/PDB/ErrorChecking.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/PDB/ErrorChecking.h?rev=275611&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/unittests/DebugInfo/PDB/ErrorChecking.h (added)
>>> +++ llvm/trunk/unittests/DebugInfo/PDB/ErrorChecking.h Fri Jul 15
>>> 15:43:38 2016
>>> @@ -0,0 +1,41 @@
>>> +//===- ErrorChecking.h - Helpers for verifying llvm::Errors -----*- C++
>>> -*-===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>>
>>> +//===----------------------------------------------------------------------===//
>>> +
>>> +#ifndef LLVM_UNITTESTS_DEBUGINFO_PDB_ERRORCHECKING_H
>>> +#define LLVM_UNITTESTS_DEBUGINFO_PDB_ERRORCHECKING_H
>>> +
>>> +#define EXPECT_NO_ERROR(Err)
>>> \
>>> + {
>>> \
>>> + auto E = Err;
>>> \
>>> + EXPECT_FALSE(static_cast<bool>(E));
>>> \
>>> + if (E)
>>> \
>>> + consumeError(std::move(E));
>>> \
>>> + }
>>> +
>>> +#define EXPECT_ERROR(Err)
>>> \
>>> + {
>>> \
>>> + auto E = Err;
>>> \
>>> + EXPECT_TRUE(static_cast<bool>(E));
>>> \
>>> + if (E)
>>> \
>>> + consumeError(std::move(E));
>>> \
>>> + }
>>> +
>>> +#define EXPECT_EXPECTED(Exp)
>>> \
>>> + {
>>> \
>>> + auto E = Exp.takeError();
>>> \
>>> + EXPECT_FALSE(static_cast<bool>(E));
>>> \
>>> + if (E) {
>>> \
>>> + consumeError(std::move(E));
>>> \
>>> + return;
>>> \
>>> + }
>>> \
>>> + }
>>> +
>>> +#define EXPECT_UNEXPECTED(Exp) EXPECT_ERROR(Err)
>>> +
>>> +#endif
>>>
>>> Modified: llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp?rev=275611&r1=275610&r2=275611&view=diff
>>>
>>> ==============================================================================
>>> --- llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
>>> (original)
>>> +++ llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp Fri Jul
>>> 15 15:43:38 2016
>>> @@ -7,7 +7,7 @@
>>> //
>>>
>>> //===----------------------------------------------------------------------===//
>>>
>>> -#include <unordered_map>
>>> +#include "ErrorChecking.h"
>>>
>>> #include "llvm/DebugInfo/CodeView/ByteStream.h"
>>> #include "llvm/DebugInfo/CodeView/StreamReader.h"
>>> @@ -19,28 +19,14 @@
>>> #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
>>> #include "gtest/gtest.h"
>>>
>>> +#include <unordered_map>
>>> +
>>> using namespace llvm;
>>> using namespace llvm::codeview;
>>> using namespace llvm::pdb;
>>>
>>> namespace {
>>>
>>> -#define EXPECT_NO_ERROR(Err)
>>> \
>>> - {
>>> \
>>> - auto E = Err;
>>> \
>>> - EXPECT_FALSE(static_cast<bool>(E));
>>> \
>>> - if (E)
>>> \
>>> - consumeError(std::move(E));
>>> \
>>> - }
>>> -
>>> -#define EXPECT_ERROR(Err)
>>> \
>>> - {
>>> \
>>> - auto E = Err;
>>> \
>>> - EXPECT_TRUE(static_cast<bool>(E));
>>> \
>>> - if (E)
>>> \
>>> - consumeError(std::move(E));
>>> \
>>> - }
>>> -
>>> static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9};
>>> static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H',
>>> 'I', 'J'};
>>>
>>>
>>> Added: llvm/trunk/unittests/DebugInfo/PDB/MsfBuilderTest.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/PDB/MsfBuilderTest.cpp?rev=275611&view=auto
>>>
>>> ==============================================================================
>>> --- llvm/trunk/unittests/DebugInfo/PDB/MsfBuilderTest.cpp (added)
>>> +++ llvm/trunk/unittests/DebugInfo/PDB/MsfBuilderTest.cpp Fri Jul 15
>>> 15:43:38 2016
>>> @@ -0,0 +1,300 @@
>>> +//===- MsfBuilderTest.cpp Tests manipulation of MSF stream metadata
>>> ------===//
>>> +//
>>> +// The LLVM Compiler Infrastructure
>>> +//
>>> +// This file is distributed under the University of Illinois Open Source
>>> +// License. See LICENSE.TXT for details.
>>> +//
>>>
>>> +//===----------------------------------------------------------------------===//
>>> +
>>> +#include "ErrorChecking.h"
>>> +
>>> +#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h"
>>> +#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h"
>>> +
>>> +#include "gtest/gtest.h"
>>> +
>>> +using namespace llvm;
>>> +using namespace llvm::pdb;
>>> +using namespace llvm::pdb::msf;
>>> +
>>> +namespace {
>>> +class MsfBuilderTest : public testing::Test {
>>> +protected:
>>> + void initializeSimpleSuperBlock(msf::SuperBlock &SB) {
>>> + initializeSuperBlock(SB);
>>> + SB.NumBlocks = 1000;
>>> + SB.NumDirectoryBytes = 8192;
>>> + }
>>> +
>>> + void initializeSuperBlock(msf::SuperBlock &SB) {
>>> + ::memset(&SB, 0, sizeof(SB));
>>> +
>>> + ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
>>> + SB.BlockMapAddr = 1;
>>> + SB.BlockSize = 4096;
>>> + SB.NumDirectoryBytes = 0;
>>> + SB.NumBlocks = 2; // one for the Super Block, one for the directory
>>> + }
>>> +
>>> + BumpPtrAllocator Allocator;
>>> +};
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, ValidateSuperBlockAccept) {
>>> + // Test that a known good super block passes validation.
>>> + SuperBlock SB;
>>> + initializeSuperBlock(SB);
>>> +
>>> + EXPECT_NO_ERROR(msf::validateSuperBlock(SB));
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, ValidateSuperBlockReject) {
>>> + // Test that various known problems cause a super block to be
>>> rejected.
>>> + SuperBlock SB;
>>> + initializeSimpleSuperBlock(SB);
>>> +
>>> + // Mismatched magic
>>> + SB.MagicBytes[0] = 8;
>>> + EXPECT_ERROR(msf::validateSuperBlock(SB));
>>> + initializeSimpleSuperBlock(SB);
>>> +
>>> + // Block 0 is reserved for super block, can't be occupied by the
>>> block map
>>> + SB.BlockMapAddr = 0;
>>> + EXPECT_ERROR(msf::validateSuperBlock(SB));
>>> + initializeSimpleSuperBlock(SB);
>>> +
>>> + // Block sizes have to be powers of 2.
>>> + SB.BlockSize = 3120;
>>> + EXPECT_ERROR(msf::validateSuperBlock(SB));
>>> + initializeSimpleSuperBlock(SB);
>>> +
>>> + // The directory itself has a maximum size.
>>> + SB.NumDirectoryBytes = SB.BlockSize * SB.BlockSize / 4;
>>> + EXPECT_NO_ERROR(msf::validateSuperBlock(SB));
>>> + SB.NumDirectoryBytes = SB.NumDirectoryBytes + 4;
>>> + EXPECT_ERROR(msf::validateSuperBlock(SB));
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestUsedBlocksMarkedAsUsed) {
>>> + // Test that when assigning a stream to a known list of blocks, the
>>> blocks
>>> + // are correctly marked as used after adding, but no other incorrect
>>> blocks
>>> + // are accidentally marked as used.
>>> +
>>> + // Allocate some extra blocks at the end so we can verify that
>>> they're free
>>> + // after the initialization.
>>> + std::vector<uint32_t> Blocks = {2, 3, 4, 5, 6, 7, 8, 9, 10};
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096, Blocks.size()
>>> + 10);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + EXPECT_NO_ERROR(Msf.addStream(Blocks.size() * 4096, Blocks));
>>> +
>>> + for (auto B : Blocks) {
>>> + EXPECT_FALSE(Msf.isBlockFree(B));
>>> + }
>>> + for (int I = 11; I < 21; ++I) {
>>> + EXPECT_TRUE(Msf.isBlockFree(I));
>>> + }
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
>>> + // Test that adding a new stream correctly updates the directory.
>>> This only
>>> + // tests the case where the directory *DOES NOT* grow large enough
>>> that it
>>> + // crosses a Block boundary.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + auto ExpectedL1 = Msf.build();
>>> + EXPECT_EXPECTED(ExpectedL1);
>>> + Layout &L1 = *ExpectedL1;
>>> +
>>> + auto OldDirBlocks = L1.DirectoryBlocks;
>>> + EXPECT_EQ(1U, OldDirBlocks.size());
>>> +
>>> + auto ExpectedMsf2 = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf2);
>>> + auto &Msf2 = *ExpectedMsf2;
>>> +
>>> + EXPECT_NO_ERROR(Msf2.addStream(4000));
>>> + EXPECT_EQ(1U, Msf2.getNumStreams());
>>> + EXPECT_EQ(4000U, Msf2.getStreamSize(0));
>>> + auto Blocks = Msf2.getStreamBlocks(0);
>>> + EXPECT_EQ(1U, Blocks.size());
>>> +
>>> + auto ExpectedL2 = Msf2.build();
>>> + EXPECT_EXPECTED(ExpectedL2);
>>> + Layout &L2 = *ExpectedL2;
>>> + auto NewDirBlocks = L2.DirectoryBlocks;
>>> + EXPECT_EQ(1U, NewDirBlocks.size());
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
>>> + // Test that adding a new stream correctly updates the directory.
>>> This only
>>> + // tests the case where the directory *DOES* grow large enough that it
>>> + // crosses a Block boundary. This is because the newly added stream
>>> occupies
>>> + // so many Blocks that need to be indexed in the directory that the
>>> directory
>>> + // crosses a Block boundary.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + EXPECT_NO_ERROR(Msf.addStream(4096 * 4096 / sizeof(uint32_t)));
>>> +
>>> + auto ExpectedL1 = Msf.build();
>>> + EXPECT_EXPECTED(ExpectedL1);
>>> + Layout &L1 = *ExpectedL1;
>>> + auto DirBlocks = L1.DirectoryBlocks;
>>> + EXPECT_EQ(2U, DirBlocks.size());
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestGrowStreamNoBlockIncrease) {
>>> + // Test growing an existing stream by a value that does not affect
>>> the number
>>> + // of blocks it occupies.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + EXPECT_NO_ERROR(Msf.addStream(1024));
>>> + EXPECT_EQ(1024U, Msf.getStreamSize(0));
>>> + auto OldStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(1U, OldStreamBlocks.size());
>>> +
>>> + EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
>>> + EXPECT_EQ(2048U, Msf.getStreamSize(0));
>>> + auto NewStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(1U, NewStreamBlocks.size());
>>> +
>>> + EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestGrowStreamWithBlockIncrease) {
>>> + // Test that growing an existing stream to a value large enough that
>>> it causes
>>> + // the need to allocate new Blocks to the stream correctly updates the
>>> + // stream's
>>> + // block list.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + EXPECT_NO_ERROR(Msf.addStream(2048));
>>> + EXPECT_EQ(2048U, Msf.getStreamSize(0));
>>> + std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(1U, OldStreamBlocks.size());
>>> +
>>> + EXPECT_NO_ERROR(Msf.setStreamSize(0, 6144));
>>> + EXPECT_EQ(6144U, Msf.getStreamSize(0));
>>> + std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(2U, NewStreamBlocks.size());
>>> +
>>> + EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
>>> + EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestShrinkStreamNoBlockDecrease) {
>>> + // Test that shrinking an existing stream by a value that does not
>>> affect the
>>> + // number of Blocks it occupies makes no changes to stream's block
>>> list.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + EXPECT_NO_ERROR(Msf.addStream(2048));
>>> + EXPECT_EQ(2048U, Msf.getStreamSize(0));
>>> + std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(1U, OldStreamBlocks.size());
>>> +
>>> + EXPECT_NO_ERROR(Msf.setStreamSize(0, 1024));
>>> + EXPECT_EQ(1024U, Msf.getStreamSize(0));
>>> + std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(1U, NewStreamBlocks.size());
>>> +
>>> + EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestShrinkStreamWithBlockDecrease) {
>>> + // Test that shrinking an existing stream to a value large enough
>>> that it
>>> + // causes the need to deallocate new Blocks to the stream correctly
>>> updates
>>> + // the stream's block list.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + EXPECT_NO_ERROR(Msf.addStream(6144));
>>> + EXPECT_EQ(6144U, Msf.getStreamSize(0));
>>> + std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(2U, OldStreamBlocks.size());
>>> +
>>> + EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
>>> + EXPECT_EQ(2048U, Msf.getStreamSize(0));
>>> + std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
>>> + EXPECT_EQ(1U, NewStreamBlocks.size());
>>> +
>>> + EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestRejectReusedStreamBlock) {
>>> + // Test that attempting to add a stream and assigning a block that is
>>> already
>>> + // in use by another stream fails.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + EXPECT_NO_ERROR(Msf.addStream(6144));
>>> +
>>> + std::vector<uint32_t> Blocks = {2, 3};
>>> + EXPECT_ERROR(Msf.addStream(6144, Blocks));
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestBlockCountsWhenAddingStreams) {
>>> + // Test that when adding multiple streams, the number of used and
>>> free Blocks
>>> + // allocated to the MSF file are as expected.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + // one for the super block, one for the directory block map
>>> + uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
>>> + EXPECT_EQ(2U, NumUsedBlocks);
>>> + EXPECT_EQ(0U, Msf.getNumFreeBlocks());
>>> +
>>> + const uint32_t StreamSizes[] = {4000, 6193, 189723};
>>> + for (int I = 0; I < 3; ++I) {
>>> + EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
>>> + NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
>>> + EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
>>> + EXPECT_EQ(0U, Msf.getNumFreeBlocks());
>>> + }
>>> +}
>>> +
>>> +TEST_F(MsfBuilderTest, TestBuildMsfLayout) {
>>> + // Test that we can generate an Msf Layout structure from a valid
>>> layout
>>> + // specification.
>>> + auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
>>> + EXPECT_EXPECTED(ExpectedMsf);
>>> + auto &Msf = *ExpectedMsf;
>>> +
>>> + const uint32_t StreamSizes[] = {4000, 6193, 189723};
>>> + uint32_t ExpectedNumBlocks = 2;
>>> + for (int I = 0; I < 3; ++I) {
>>> + EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
>>> + ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
>>> + }
>>> + ++ExpectedNumBlocks; // The directory itself should use 1 block
>>> +
>>> + auto ExpectedLayout = Msf.build();
>>> + EXPECT_EXPECTED(ExpectedLayout);
>>> + Layout &L = *ExpectedLayout;
>>> + EXPECT_EQ(4096U, L.SB->BlockSize);
>>> + EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
>>> +
>>> + EXPECT_EQ(1U, L.DirectoryBlocks.size());
>>> +
>>> + EXPECT_EQ(3U, L.StreamMap.size());
>>> + EXPECT_EQ(3U, L.StreamSizes.size());
>>> + for (int I = 0; I < 3; ++I) {
>>> + EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);
>>> + uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);
>>> + EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
>>> + }
>>> +}
>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160715/37a3ca6f/attachment.html>
More information about the llvm-commits
mailing list