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