[llvm] r309896 - [pdb/lld] Write a valid FPM.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 2 15:31:39 PDT 2017


Author: zturner
Date: Wed Aug  2 15:31:39 2017
New Revision: 309896

URL: http://llvm.org/viewvc/llvm-project?rev=309896&view=rev
Log:
[pdb/lld] Write a valid FPM.

The PDB reserves certain blocks for the FPM that describe which
blocks in the file are allocated and which are free.  We weren't
filling that out at all, and in some cases we were even stomping
it with incorrect data.  This patch writes a correct FPM.

Differential Revision: https://reviews.llvm.org/D36235

Added:
    llvm/trunk/test/DebugInfo/PDB/write-fpm.test
    llvm/trunk/unittests/DebugInfo/MSF/MSFCommonTest.cpp
Modified:
    llvm/trunk/include/llvm/DebugInfo/MSF/MSFCommon.h
    llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h
    llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h
    llvm/trunk/include/llvm/Support/MathExtras.h
    llvm/trunk/lib/DebugInfo/MSF/MSFBuilder.cpp
    llvm/trunk/lib/DebugInfo/MSF/MSFCommon.cpp
    llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp
    llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp
    llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
    llvm/trunk/unittests/DebugInfo/MSF/CMakeLists.txt
    llvm/trunk/unittests/DebugInfo/MSF/MSFBuilderTest.cpp
    llvm/trunk/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/MSF/MSFCommon.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/MSF/MSFCommon.h?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/MSF/MSFCommon.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/MSF/MSFCommon.h Wed Aug  2 15:31:39 2017
@@ -74,7 +74,9 @@ public:
 /// \brief Determine the layout of the FPM stream, given the MSF layout.  An FPM
 /// stream spans 1 or more blocks, each at equally spaced intervals throughout
 /// the file.
-MSFStreamLayout getFpmStreamLayout(const MSFLayout &Msf);
+MSFStreamLayout getFpmStreamLayout(const MSFLayout &Msf,
+                                   bool IncludeUnusedFpmData = false,
+                                   bool AltFpm = false);
 
 inline bool isValidBlockSize(uint32_t Size) {
   switch (Size) {
@@ -95,7 +97,7 @@ inline uint32_t getMinimumBlockCount() {
 inline uint32_t getFirstUnreservedBlock() { return 3; }
 
 inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
-  return alignTo(NumBytes, BlockSize) / BlockSize;
+  return divideCeil(NumBytes, BlockSize);
 }
 
 inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) {
@@ -106,13 +108,14 @@ inline uint32_t getFpmIntervalLength(con
   return L.SB->BlockSize;
 }
 
-inline uint32_t getNumFpmIntervals(const MSFLayout &L) {
-  uint32_t Length = getFpmIntervalLength(L);
-  return alignTo(L.SB->NumBlocks, Length) / Length;
-}
-
-inline uint32_t getFullFpmByteSize(const MSFLayout &L) {
-  return alignTo(L.SB->NumBlocks, 8) / 8;
+inline uint32_t getNumFpmIntervals(const MSFLayout &L,
+                                   bool IncludeUnusedFpmData = false) {
+  if (IncludeUnusedFpmData)
+    return divideCeil(L.SB->NumBlocks, L.SB->BlockSize);
+
+  // We want the minimum number of intervals required, where each interval can
+  // represent BlockSize * 8 blocks.
+  return divideCeil(L.SB->NumBlocks, 8 * L.SB->BlockSize);
 }
 
 Error validateSuperBlock(const SuperBlock &SB);

Modified: llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h Wed Aug  2 15:31:39 2017
@@ -122,7 +122,7 @@ public:
 
   static std::unique_ptr<WritableMappedBlockStream>
   createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData,
-                  BumpPtrAllocator &Allocator);
+                  BumpPtrAllocator &Allocator, bool AltFpm = false);
 
   support::endianness getEndian() const override {
     return support::little;

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFileBuilder.h Wed Aug  2 15:31:39 2017
@@ -61,6 +61,8 @@ public:
 private:
   Expected<msf::MSFLayout> finalizeMsfLayout();
 
+  void commitFpm(WritableBinaryStream &MsfBuffer, const msf::MSFLayout &Layout);
+
   BumpPtrAllocator &Allocator;
 
   std::unique_ptr<msf::MSFBuilder> Msf;

Modified: llvm/trunk/include/llvm/Support/MathExtras.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MathExtras.h?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/MathExtras.h (original)
+++ llvm/trunk/include/llvm/Support/MathExtras.h Wed Aug  2 15:31:39 2017
@@ -687,6 +687,11 @@ template <uint64_t Align> constexpr inli
   return (Value + Align - 1) / Align * Align;
 }
 
+/// Returns the integer ceil(Numerator / Denominator).
+inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
+  return alignTo(Numerator, Denominator) / Denominator;
+}
+
 /// \c alignTo for contexts where a constant expression is required.
 /// \sa alignTo
 ///

Modified: llvm/trunk/lib/DebugInfo/MSF/MSFBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/MSF/MSFBuilder.cpp?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/MSF/MSFBuilder.cpp (original)
+++ llvm/trunk/lib/DebugInfo/MSF/MSFBuilder.cpp Wed Aug  2 15:31:39 2017
@@ -107,7 +107,23 @@ Error MSFBuilder::allocateBlocks(uint32_
       return make_error<MSFError>(msf_error_code::insufficient_buffer,
                                   "There are no free Blocks in the file");
     uint32_t AllocBlocks = NumBlocks - NumFreeBlocks;
-    FreeBlocks.resize(AllocBlocks + FreeBlocks.size(), true);
+    uint32_t OldBlockCount = FreeBlocks.size();
+    uint32_t NewBlockCount = AllocBlocks + OldBlockCount;
+    uint32_t NextFpmBlock = alignTo(OldBlockCount, BlockSize) + 1;
+    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.
+    while (NextFpmBlock < NewBlockCount) {
+      NewBlockCount += 2;
+      FreeBlocks.resize(NewBlockCount, true);
+      FreeBlocks.reset(NextFpmBlock, NextFpmBlock + 2);
+      NextFpmBlock += BlockSize;
+    }
   }
 
   int I = 0;
@@ -229,6 +245,19 @@ uint32_t MSFBuilder::computeDirectoryByt
   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() {
   SuperBlock *SB = Allocator.Allocate<SuperBlock>();
   MSFLayout L;
@@ -287,5 +316,20 @@ 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;
 }

Modified: llvm/trunk/lib/DebugInfo/MSF/MSFCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/MSF/MSFCommon.cpp?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/MSF/MSFCommon.cpp (original)
+++ llvm/trunk/lib/DebugInfo/MSF/MSFCommon.cpp Wed Aug  2 15:31:39 2017
@@ -60,17 +60,26 @@ Error llvm::msf::validateSuperBlock(cons
   return Error::success();
 }
 
-MSFStreamLayout llvm::msf::getFpmStreamLayout(const MSFLayout &Msf) {
+MSFStreamLayout llvm::msf::getFpmStreamLayout(const MSFLayout &Msf,
+                                              bool IncludeUnusedFpmData,
+                                              bool AltFpm) {
   MSFStreamLayout FL;
-  uint32_t NumFpmIntervals = getNumFpmIntervals(Msf);
+  uint32_t NumFpmIntervals = getNumFpmIntervals(Msf, IncludeUnusedFpmData);
   support::ulittle32_t FpmBlock = Msf.SB->FreeBlockMapBlock;
   assert(FpmBlock == 1 || FpmBlock == 2);
-  while (NumFpmIntervals > 0) {
+  if (AltFpm) {
+    // If they requested the alternate FPM, then 2 becomes 1 and 1 becomes 2.
+    FpmBlock = 3U - FpmBlock;
+  }
+  for (uint32_t I = 0; I < NumFpmIntervals; ++I) {
     FL.Blocks.push_back(FpmBlock);
     FpmBlock += msf::getFpmIntervalLength(Msf);
-    --NumFpmIntervals;
   }
-  FL.Length = getFullFpmByteSize(Msf);
+
+  if (IncludeUnusedFpmData)
+    FL.Length = NumFpmIntervals * Msf.SB->BlockSize;
+  else
+    FL.Length = divideCeil(Msf.SB->NumBlocks, 8);
 
   return FL;
 }

Modified: llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp Wed Aug  2 15:31:39 2017
@@ -11,6 +11,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/Support/BinaryStreamWriter.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MathExtras.h"
@@ -347,9 +348,27 @@ WritableMappedBlockStream::createDirecto
 std::unique_ptr<WritableMappedBlockStream>
 WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout,
                                            WritableBinaryStreamRef MsfData,
-                                           BumpPtrAllocator &Allocator) {
-  MSFStreamLayout SL(getFpmStreamLayout(Layout));
-  return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
+                                           BumpPtrAllocator &Allocator,
+                                           bool AltFpm) {
+  // We only want to give the user a stream containing the bytes of the FPM that
+  // are actually valid, but we want to initialize all of the bytes, even those
+  // that come from reserved FPM blocks where the entire block is unused.  To do
+  // this, we first create the full layout, which gives us a stream with all
+  // bytes and all blocks, and initialize everything to 0xFF (all blocks in the
+  // file are unused).  Then we create the minimal layout (which contains only a
+  // subset of the bytes previously initialized), and return that to the user.
+  MSFStreamLayout MinLayout(getFpmStreamLayout(Layout, false, AltFpm));
+
+  MSFStreamLayout FullLayout(getFpmStreamLayout(Layout, true, AltFpm));
+  auto Result =
+      createStream(Layout.SB->BlockSize, FullLayout, MsfData, Allocator);
+  if (!Result)
+    return Result;
+  std::vector<uint8_t> InitData(Layout.SB->BlockSize, 0xFF);
+  BinaryStreamWriter Initializer(*Result);
+  while (Initializer.bytesRemaining() > 0)
+    cantFail(Initializer.writeBytes(InitData));
+  return createStream(Layout.SB->BlockSize, MinLayout, MsfData, Allocator);
 }
 
 Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size,

Modified: llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp Wed Aug  2 15:31:39 2017
@@ -150,8 +150,7 @@ Error PDBFile::parseFileHeaders() {
       MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
   BinaryStreamReader FpmReader(*FpmStream);
   ArrayRef<uint8_t> FpmBytes;
-  if (auto EC = FpmReader.readBytes(FpmBytes,
-                                    msf::getFullFpmByteSize(ContainerLayout)))
+  if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
     return EC;
   uint32_t BlocksRemaining = getBlockCount();
   uint32_t BI = 0;

Modified: llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp Wed Aug  2 15:31:39 2017
@@ -155,6 +155,31 @@ Expected<uint32_t> PDBFileBuilder::getNa
   return SN;
 }
 
+void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
+                               const MSFLayout &Layout) {
+  auto FpmStream =
+      WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
+
+  // We only need to create the alt fpm stream so that it gets initialized.
+  WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
+                                             true);
+
+  uint32_t BI = 0;
+  BinaryStreamWriter FpmWriter(*FpmStream);
+  while (BI < Layout.SB->NumBlocks) {
+    uint8_t ThisByte = 0;
+    for (uint32_t I = 0; I < 8; ++I) {
+      bool IsFree =
+          (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
+      uint8_t Mask = uint8_t(IsFree) << I;
+      ThisByte |= Mask;
+      ++BI;
+    }
+    cantFail(FpmWriter.writeObject(ThisByte));
+  }
+  assert(FpmWriter.bytesRemaining() == 0);
+}
+
 Error PDBFileBuilder::commit(StringRef Filename) {
   assert(!Filename.empty());
   auto ExpectedLayout = finalizeMsfLayout();
@@ -173,6 +198,9 @@ Error PDBFileBuilder::commit(StringRef F
 
   if (auto EC = Writer.writeObject(*Layout.SB))
     return EC;
+
+  commitFpm(Buffer, Layout);
+
   uint32_t BlockMapOffset =
       msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
   Writer.setOffset(BlockMapOffset);

Added: llvm/trunk/test/DebugInfo/PDB/write-fpm.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/DebugInfo/PDB/write-fpm.test?rev=309896&view=auto
==============================================================================
--- llvm/trunk/test/DebugInfo/PDB/write-fpm.test (added)
+++ llvm/trunk/test/DebugInfo/PDB/write-fpm.test Wed Aug  2 15:31:39 2017
@@ -0,0 +1,11 @@
+; RUN: llvm-pdbutil yaml2pdb -pdb=%t.pdb %p/Inputs/one-symbol.yaml
+; RUN: llvm-pdbutil bytes -fpm %t.pdb | FileCheck %s
+
+
+CHECK:                             Free Page Map
+CHECK-NEXT: ============================================================
+CHECK-NEXT: Block 1 (
+CHECK-NEXT:   1000: 04F8FFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
+CHECK-NEXT:   1020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
+CHECK:        1FE0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF  |................................|
+CHECK:      )

Modified: llvm/trunk/unittests/DebugInfo/MSF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/MSF/CMakeLists.txt?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/MSF/CMakeLists.txt (original)
+++ llvm/trunk/unittests/DebugInfo/MSF/CMakeLists.txt Wed Aug  2 15:31:39 2017
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
 set(DebugInfoMSFSources
   MappedBlockStreamTest.cpp
   MSFBuilderTest.cpp
+  MSFCommonTest.cpp
   )
 
 add_llvm_unittest(DebugInfoMSFTests

Modified: llvm/trunk/unittests/DebugInfo/MSF/MSFBuilderTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/MSF/MSFBuilderTest.cpp?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/MSF/MSFBuilderTest.cpp (original)
+++ llvm/trunk/unittests/DebugInfo/MSF/MSFBuilderTest.cpp Wed Aug  2 15:31:39 2017
@@ -11,10 +11,13 @@
 #include "llvm/DebugInfo/MSF/MSFCommon.h"
 #include "llvm/Testing/Support/Error.h"
 
+#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
 using namespace llvm::msf;
+using namespace testing;
 
 namespace {
 class MSFBuilderTest : public testing::Test {
@@ -359,3 +362,36 @@ TEST_F(MSFBuilderTest, DirectoryBlockHin
   EXPECT_EQ(1U, L.DirectoryBlocks.size());
   EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
 }
+
+TEST_F(MSFBuilderTest, StreamDoesntUseFpmBlocks) {
+  Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(Allocator, 4096);
+  ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());
+  auto &Msf = *ExpectedMsf;
+
+  // A block is 4096 bytes, and every 4096 blocks we have 2 reserved FPM blocks.
+  // By creating add a stream that spans 4096*4096*3 bytes, we ensure that we
+  // cross over a couple of reserved FPM blocks, and that none of them are
+  // allocated to the stream.
+  constexpr uint32_t StreamSize = 4096 * 4096 * 3;
+  Expected<uint32_t> SN = Msf.addStream(StreamSize);
+  ASSERT_THAT_EXPECTED(SN, Succeeded());
+
+  auto ExpectedLayout = Msf.build();
+  ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
+  MSFLayout &L = *ExpectedLayout;
+  auto BlocksRef = L.StreamMap[*SN];
+  std::vector<uint32_t> Blocks(BlocksRef.begin(), BlocksRef.end());
+  EXPECT_EQ(StreamSize, L.StreamSizes[*SN]);
+
+  for (uint32_t I = 0; I <= 3; ++I) {
+    // Pages from the regular FPM are allocated, while pages from the alt fpm
+    // are free.
+    EXPECT_FALSE(L.FreePageMap.test(1 + I * 4096));
+    EXPECT_TRUE(L.FreePageMap.test(2 + I * 4096));
+  }
+
+  for (uint32_t I = 1; I <= 3; ++I) {
+    EXPECT_THAT(Blocks, Not(Contains(1 + I * 4096)));
+    EXPECT_THAT(Blocks, Not(Contains(2 + I * 4096)));
+  }
+}

Added: llvm/trunk/unittests/DebugInfo/MSF/MSFCommonTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/MSF/MSFCommonTest.cpp?rev=309896&view=auto
==============================================================================
--- llvm/trunk/unittests/DebugInfo/MSF/MSFCommonTest.cpp (added)
+++ llvm/trunk/unittests/DebugInfo/MSF/MSFCommonTest.cpp Wed Aug  2 15:31:39 2017
@@ -0,0 +1,104 @@
+//===- 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 "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::msf;
+
+TEST(MSFCommonTest, BytesToBlocks) {
+  EXPECT_EQ(0ULL, bytesToBlocks(0, 4096));
+  EXPECT_EQ(1ULL, bytesToBlocks(12, 4096));
+  EXPECT_EQ(1ULL, bytesToBlocks(4096, 4096));
+  EXPECT_EQ(2ULL, bytesToBlocks(4097, 4096));
+  EXPECT_EQ(2ULL, bytesToBlocks(600, 512));
+}
+
+TEST(MSFCommonTest, FpmIntervals) {
+  SuperBlock SB;
+  SB.FreeBlockMapBlock = 1;
+  SB.BlockSize = 4096;
+
+  MSFLayout L;
+  L.SB = &SB;
+
+  SB.NumBlocks = 12;
+  EXPECT_EQ(1u, getNumFpmIntervals(L, false));
+  SB.NumBlocks = SB.BlockSize;
+  EXPECT_EQ(1u, getNumFpmIntervals(L, false));
+  SB.NumBlocks = SB.BlockSize + 1;
+  EXPECT_EQ(1u, getNumFpmIntervals(L, false));
+  SB.NumBlocks = SB.BlockSize * 8;
+  EXPECT_EQ(1u, getNumFpmIntervals(L, false));
+  SB.NumBlocks = SB.BlockSize * 8 + 1;
+  EXPECT_EQ(2u, getNumFpmIntervals(L, false));
+
+  SB.NumBlocks = 12;
+  EXPECT_EQ(1u, getNumFpmIntervals(L, true));
+  SB.NumBlocks = SB.BlockSize;
+  EXPECT_EQ(1u, getNumFpmIntervals(L, true));
+  SB.NumBlocks = SB.BlockSize + 1;
+  EXPECT_EQ(2u, getNumFpmIntervals(L, true));
+  SB.NumBlocks = SB.BlockSize * 8;
+  EXPECT_EQ(8u, getNumFpmIntervals(L, true));
+  SB.NumBlocks = SB.BlockSize * 8 + 1;
+  EXPECT_EQ(9u, getNumFpmIntervals(L, true));
+}
+
+TEST(MSFCommonTest, FpmStreamLayout) {
+  SuperBlock SB;
+  MSFLayout L;
+  L.SB = &SB;
+  SB.FreeBlockMapBlock = 1;
+
+  // Each FPM block has 4096 bytes for a maximum of 4096*8 allocation states.
+  SB.BlockSize = 4096;
+
+  // 1. When we're not including unused FPM data, the length of the FPM stream
+  //    should be only long enough to contain 1 bit for each block.
+
+  // 1a. When the PDB has <= 4096*8 blocks, there should only be one FPM block.
+  SB.NumBlocks = 8000;
+  MSFStreamLayout SL = getFpmStreamLayout(L, false, false);
+  EXPECT_EQ(1000u, SL.Length);
+  EXPECT_EQ(1u, SL.Blocks.size());
+  EXPECT_EQ(SB.FreeBlockMapBlock, SL.Blocks.front());
+
+  SL = getFpmStreamLayout(L, false, true);
+  EXPECT_EQ(1000u, SL.Length);
+  EXPECT_EQ(1u, SL.Blocks.size());
+  EXPECT_EQ(3u - SB.FreeBlockMapBlock, SL.Blocks.front());
+
+  // 1b. When the PDB has > 4096*8 blocks, there should be multiple FPM blocks.
+  SB.NumBlocks = SB.BlockSize * 8 + 1;
+  SL = getFpmStreamLayout(L, false, false);
+  EXPECT_EQ(SB.BlockSize + 1, SL.Length);
+  EXPECT_EQ(2u, SL.Blocks.size());
+  EXPECT_EQ(SB.FreeBlockMapBlock, SL.Blocks[0]);
+  EXPECT_EQ(SB.FreeBlockMapBlock + SB.BlockSize, SL.Blocks[1]);
+
+  SL = getFpmStreamLayout(L, false, true);
+  EXPECT_EQ(SB.BlockSize + 1, SL.Length);
+  EXPECT_EQ(2u, SL.Blocks.size());
+  EXPECT_EQ(3u - SB.FreeBlockMapBlock, SL.Blocks[0]);
+  EXPECT_EQ(3u - SB.FreeBlockMapBlock + SB.BlockSize, SL.Blocks[1]);
+
+  // 2. When we are including unused FPM data, there should be one FPM block
+  //    at every BlockSize interval in the file, even if entire FPM blocks are
+  //    unused.
+  SB.NumBlocks = SB.BlockSize * 8 + 1;
+  SL = getFpmStreamLayout(L, true, false);
+  EXPECT_EQ(SB.BlockSize * 9, SL.Length);
+  EXPECT_EQ(9u, SL.Blocks.size());
+  for (int I = 0; I < 9; ++I)
+    EXPECT_EQ(I * SB.BlockSize + SB.FreeBlockMapBlock, SL.Blocks[I]);
+}

Modified: llvm/trunk/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp?rev=309896&r1=309895&r2=309896&view=diff
==============================================================================
--- llvm/trunk/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp (original)
+++ llvm/trunk/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp Wed Aug  2 15:31:39 2017
@@ -16,6 +16,7 @@
 #include "llvm/Support/BinaryStreamWriter.h"
 #include "llvm/Testing/Support/Error.h"
 
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 #include <unordered_map>
@@ -494,5 +495,59 @@ TEST(MappedBlockStreamTest, DataLivesAft
 
   EXPECT_EQ(Str[0], Str[1]);
 }
+} // namespace
+
+MATCHER_P3(BlockIsFilledWith, Layout, BlockIndex, Byte, "succeeded") {
+  uint64_t Offset = msf::blockToOffset(BlockIndex, Layout.SB->BlockSize);
+  ArrayRef<uint8_t> BufferRef = makeArrayRef(arg);
+  BufferRef = BufferRef.slice(Offset, Layout.SB->BlockSize);
+  return llvm::all_of(BufferRef, [this](uint8_t B) { return B == Byte; });
+}
+
+namespace {
+TEST(MappedBlockStreamTest, CreateFpmStream) {
+  BumpPtrAllocator Allocator;
+  SuperBlock SB;
+  MSFLayout L;
+  L.SB = &SB;
+
+  SB.FreeBlockMapBlock = 1;
+  SB.BlockSize = 4096;
+
+  constexpr uint32_t NumFileBlocks = 4096 * 4;
+
+  std::vector<uint8_t> MsfBuffer(NumFileBlocks * SB.BlockSize);
+  MutableBinaryByteStream MsfStream(MsfBuffer, llvm::support::little);
+
+  SB.NumBlocks = NumFileBlocks;
+  auto FpmStream =
+      WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator);
+  // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
+  // blocks.  This translates to 1 FPM block.
+  EXPECT_EQ(2048u, FpmStream->getLength());
+  EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
+  EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks[0]);
+  // All blocks from FPM1 should be 1 initialized, and all blocks from FPM2
+  // should be 0 initialized (since we requested the main FPM, not the alt FPM)
+  for (int I = 0; I < 4; ++I) {
+    EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0xFF));
+    EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0));
+  }
+
+  ::memset(MsfBuffer.data(), 0, MsfBuffer.size());
+  FpmStream =
+      WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator, true);
+  // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
+  // blocks.  This translates to 1 FPM block.
+  EXPECT_EQ(2048u, FpmStream->getLength());
+  EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
+  EXPECT_EQ(2u, FpmStream->getStreamLayout().Blocks[0]);
+  // All blocks from FPM2 should be 1 initialized, and all blocks from FPM1
+  // should be 0 initialized (since we requested the alt FPM, not the main FPM)
+  for (int I = 0; I < 4; ++I) {
+    EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0));
+    EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0xFF));
+  }
+}
 
 } // end anonymous namespace




More information about the llvm-commits mailing list