brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.3 KiB · f327fef Raw
396 lines · cpp
1//===- MSFBuilderTest.cpp  Tests manipulation of MSF stream metadata ------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/MSF/MSFBuilder.h"10#include "llvm/DebugInfo/MSF/MSFCommon.h"11#include "llvm/Testing/Support/Error.h"12 13#include "gmock/gmock-matchers.h"14#include "gmock/gmock.h"15#include "gtest/gtest.h"16 17using namespace llvm;18using namespace llvm::msf;19using namespace testing;20 21namespace {22class MSFBuilderTest : public testing::Test {23protected:24  void initializeSimpleSuperBlock(msf::SuperBlock &SB) {25    initializeSuperBlock(SB);26    SB.NumBlocks = 1000;27    SB.NumDirectoryBytes = 8192;28  }29 30  void initializeSuperBlock(msf::SuperBlock &SB) {31    ::memset(&SB, 0, sizeof(SB));32 33    ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));34    SB.FreeBlockMapBlock = 1;35    SB.BlockMapAddr = 1;36    SB.BlockSize = 4096;37    SB.NumDirectoryBytes = 0;38    SB.NumBlocks = 2; // one for the Super Block, one for the directory39  }40 41  BumpPtrAllocator Allocator;42};43} // namespace44 45TEST_F(MSFBuilderTest, ValidateSuperBlockAccept) {46  // Test that a known good super block passes validation.47  SuperBlock SB;48  initializeSuperBlock(SB);49 50  EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());51}52 53TEST_F(MSFBuilderTest, ValidateSuperBlockReject) {54  // Test that various known problems cause a super block to be rejected.55  SuperBlock SB;56  initializeSimpleSuperBlock(SB);57 58  // Mismatched magic59  SB.MagicBytes[0] = 8;60  EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());61  initializeSimpleSuperBlock(SB);62 63  // Block 0 is reserved for super block, can't be occupied by the block map64  SB.BlockMapAddr = 0;65  EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());66  initializeSimpleSuperBlock(SB);67 68  // Block sizes have to be powers of 2.69  SB.BlockSize = 3120;70  EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());71  initializeSimpleSuperBlock(SB);72 73  // The directory itself has a maximum size.74  SB.NumDirectoryBytes = SB.BlockSize * SB.BlockSize / 4;75  EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());76  SB.NumDirectoryBytes = SB.NumDirectoryBytes + 4;77  EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());78}79 80TEST_F(MSFBuilderTest, TestUsedBlocksMarkedAsUsed) {81  // Test that when assigning a stream to a known list of blocks, the blocks82  // are correctly marked as used after adding, but no other incorrect blocks83  // are accidentally marked as used.84 85  std::vector<uint32_t> Blocks = {4, 5, 6, 7, 8, 9, 10, 11, 12};86  // Allocate some extra blocks at the end so we can verify that they're free87  // after the initialization.88  uint32_t NumBlocks = msf::getMinimumBlockCount() + Blocks.size() + 10;89  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096, NumBlocks);90  ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());91  auto &Msf = *ExpectedMsf;92 93  EXPECT_THAT_EXPECTED(Msf.addStream(Blocks.size() * 4096, Blocks),94                       Succeeded());95 96  for (auto B : Blocks) {97    EXPECT_FALSE(Msf.isBlockFree(B));98  }99 100  uint32_t FreeBlockStart = Blocks.back() + 1;101  for (uint32_t I = FreeBlockStart; I < NumBlocks; ++I) {102    EXPECT_TRUE(Msf.isBlockFree(I));103  }104}105 106TEST_F(MSFBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {107  // Test that adding a new stream correctly updates the directory.  This only108  // tests the case where the directory *DOES NOT* grow large enough that it109  // crosses a Block boundary.110  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);111  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());112  auto &Msf = *ExpectedMsf;113 114  auto ExpectedL1 = Msf.generateLayout();115  EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());116  MSFLayout &L1 = *ExpectedL1;117 118  auto OldDirBlocks = L1.DirectoryBlocks;119  EXPECT_EQ(1U, OldDirBlocks.size());120 121  auto ExpectedMsf2 = MSFBuilder::create(Allocator, 4096);122  EXPECT_THAT_EXPECTED(ExpectedMsf2, Succeeded());123  auto &Msf2 = *ExpectedMsf2;124 125  EXPECT_THAT_EXPECTED(Msf2.addStream(4000), Succeeded());126  EXPECT_EQ(1U, Msf2.getNumStreams());127  EXPECT_EQ(4000U, Msf2.getStreamSize(0));128  auto Blocks = Msf2.getStreamBlocks(0);129  EXPECT_EQ(1U, Blocks.size());130 131  auto ExpectedL2 = Msf2.generateLayout();132  EXPECT_THAT_EXPECTED(ExpectedL2, Succeeded());133  MSFLayout &L2 = *ExpectedL2;134  auto NewDirBlocks = L2.DirectoryBlocks;135  EXPECT_EQ(1U, NewDirBlocks.size());136}137 138TEST_F(MSFBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {139  // Test that adding a new stream correctly updates the directory.  This only140  // tests the case where the directory *DOES* grow large enough that it141  // crosses a Block boundary.  This is because the newly added stream occupies142  // so many Blocks that need to be indexed in the directory that the directory143  // crosses a Block boundary.144  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);145  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());146  auto &Msf = *ExpectedMsf;147 148  EXPECT_THAT_EXPECTED(Msf.addStream(4096 * 4096 / sizeof(uint32_t)),149                       Succeeded());150 151  auto ExpectedL1 = Msf.generateLayout();152  EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());153  MSFLayout &L1 = *ExpectedL1;154  auto DirBlocks = L1.DirectoryBlocks;155  EXPECT_EQ(2U, DirBlocks.size());156}157 158TEST_F(MSFBuilderTest, TestGrowStreamNoBlockIncrease) {159  // Test growing an existing stream by a value that does not affect the number160  // of blocks it occupies.161  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);162  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());163  auto &Msf = *ExpectedMsf;164 165  EXPECT_THAT_EXPECTED(Msf.addStream(1024), Succeeded());166  EXPECT_EQ(1024U, Msf.getStreamSize(0));167  auto OldStreamBlocks = Msf.getStreamBlocks(0);168  EXPECT_EQ(1U, OldStreamBlocks.size());169 170  EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());171  EXPECT_EQ(2048U, Msf.getStreamSize(0));172  auto NewStreamBlocks = Msf.getStreamBlocks(0);173  EXPECT_EQ(1U, NewStreamBlocks.size());174 175  EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);176}177 178TEST_F(MSFBuilderTest, TestGrowStreamWithBlockIncrease) {179  // Test that growing an existing stream to a value large enough that it causes180  // the need to allocate new Blocks to the stream correctly updates the181  // stream's182  // block list.183  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);184  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());185  auto &Msf = *ExpectedMsf;186 187  EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());188  EXPECT_EQ(2048U, Msf.getStreamSize(0));189  std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);190  EXPECT_EQ(1U, OldStreamBlocks.size());191 192  EXPECT_THAT_ERROR(Msf.setStreamSize(0, 6144), Succeeded());193  EXPECT_EQ(6144U, Msf.getStreamSize(0));194  std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);195  EXPECT_EQ(2U, NewStreamBlocks.size());196 197  EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);198  EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);199}200 201TEST_F(MSFBuilderTest, TestShrinkStreamNoBlockDecrease) {202  // Test that shrinking an existing stream by a value that does not affect the203  // number of Blocks it occupies makes no changes to stream's block list.204  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);205  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());206  auto &Msf = *ExpectedMsf;207 208  EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());209  EXPECT_EQ(2048U, Msf.getStreamSize(0));210  std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);211  EXPECT_EQ(1U, OldStreamBlocks.size());212 213  EXPECT_THAT_ERROR(Msf.setStreamSize(0, 1024), Succeeded());214  EXPECT_EQ(1024U, Msf.getStreamSize(0));215  std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);216  EXPECT_EQ(1U, NewStreamBlocks.size());217 218  EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);219}220 221TEST_F(MSFBuilderTest, TestShrinkStreamWithBlockDecrease) {222  // Test that shrinking an existing stream to a value large enough that it223  // causes the need to deallocate new Blocks to the stream correctly updates224  // the stream's block list.225  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);226  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());227  auto &Msf = *ExpectedMsf;228 229  EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());230  EXPECT_EQ(6144U, Msf.getStreamSize(0));231  std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);232  EXPECT_EQ(2U, OldStreamBlocks.size());233 234  EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());235  EXPECT_EQ(2048U, Msf.getStreamSize(0));236  std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);237  EXPECT_EQ(1U, NewStreamBlocks.size());238 239  EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);240}241 242TEST_F(MSFBuilderTest, TestRejectReusedStreamBlock) {243  // Test that attempting to add a stream and assigning a block that is already244  // in use by another stream fails.245  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);246  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());247  auto &Msf = *ExpectedMsf;248 249  EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());250 251  std::vector<uint32_t> Blocks = {2, 3};252  EXPECT_THAT_EXPECTED(Msf.addStream(6144, Blocks), Failed());253}254 255TEST_F(MSFBuilderTest, TestBlockCountsWhenAddingStreams) {256  // Test that when adding multiple streams, the number of used and free Blocks257  // allocated to the MSF file are as expected.258  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);259  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());260  auto &Msf = *ExpectedMsf;261 262  // one for the super block, one for the directory block map263  uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();264  EXPECT_EQ(msf::getMinimumBlockCount(), NumUsedBlocks);265  EXPECT_EQ(0U, Msf.getNumFreeBlocks());266 267  const uint32_t StreamSizes[] = {4000, 6193, 189723};268  for (int I = 0; I < 3; ++I) {269    EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());270    NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);271    EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());272    EXPECT_EQ(0U, Msf.getNumFreeBlocks());273  }274}275 276TEST_F(MSFBuilderTest, BuildMsfLayout) {277  // Test that we can generate an MSFLayout structure from a valid layout278  // specification.279  auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);280  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());281  auto &Msf = *ExpectedMsf;282 283  const uint32_t StreamSizes[] = {4000, 6193, 189723};284  uint32_t ExpectedNumBlocks = msf::getMinimumBlockCount();285  for (int I = 0; I < 3; ++I) {286    EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());287    ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);288  }289  ++ExpectedNumBlocks; // The directory itself should use 1 block290 291  auto ExpectedLayout = Msf.generateLayout();292  EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());293  MSFLayout &L = *ExpectedLayout;294  EXPECT_EQ(4096U, L.SB->BlockSize);295  EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);296 297  EXPECT_EQ(1U, L.DirectoryBlocks.size());298 299  EXPECT_EQ(3U, L.StreamMap.size());300  EXPECT_EQ(3U, L.StreamSizes.size());301  for (int I = 0; I < 3; ++I) {302    EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);303    uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);304    EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());305  }306}307 308TEST_F(MSFBuilderTest, UseDirectoryBlockHint) {309  Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(310      Allocator, 4096, msf::getMinimumBlockCount() + 1, false);311  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());312  auto &Msf = *ExpectedMsf;313 314  uint32_t B = msf::getFirstUnreservedBlock();315  EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());316  EXPECT_THAT_EXPECTED(Msf.addStream(2048, {B + 2}), Succeeded());317 318  auto ExpectedLayout = Msf.generateLayout();319  EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());320  MSFLayout &L = *ExpectedLayout;321  EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);322  EXPECT_EQ(1U, L.DirectoryBlocks.size());323  EXPECT_EQ(1U, L.StreamMap[0].size());324 325  EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);326  EXPECT_EQ(B + 2, L.StreamMap[0].front());327}328 329TEST_F(MSFBuilderTest, DirectoryBlockHintInsufficient) {330  Expected<MSFBuilder> ExpectedMsf =331      MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);332  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());333  auto &Msf = *ExpectedMsf;334  uint32_t B = msf::getFirstUnreservedBlock();335  EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());336 337  uint32_t Size = 4096 * 4096 / 4;338  EXPECT_THAT_EXPECTED(Msf.addStream(Size), Succeeded());339 340  auto ExpectedLayout = Msf.generateLayout();341  EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());342  MSFLayout &L = *ExpectedLayout;343  EXPECT_EQ(2U, L.DirectoryBlocks.size());344  EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);345}346 347TEST_F(MSFBuilderTest, DirectoryBlockHintOverestimated) {348  Expected<MSFBuilder> ExpectedMsf =349      MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);350  EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());351  auto &Msf = *ExpectedMsf;352 353  uint32_t B = msf::getFirstUnreservedBlock();354  EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1, B + 2}), Succeeded());355 356  ASSERT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());357 358  auto ExpectedLayout = Msf.generateLayout();359  ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());360  MSFLayout &L = *ExpectedLayout;361  EXPECT_EQ(1U, L.DirectoryBlocks.size());362  EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);363}364 365TEST_F(MSFBuilderTest, StreamDoesntUseFpmBlocks) {366  Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(Allocator, 4096);367  ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());368  auto &Msf = *ExpectedMsf;369 370  // A block is 4096 bytes, and every 4096 blocks we have 2 reserved FPM blocks.371  // By creating add a stream that spans 4096*4096*3 bytes, we ensure that we372  // cross over a couple of reserved FPM blocks, and that none of them are373  // allocated to the stream.374  constexpr uint32_t StreamSize = 4096 * 4096 * 3;375  Expected<uint32_t> SN = Msf.addStream(StreamSize);376  ASSERT_THAT_EXPECTED(SN, Succeeded());377 378  auto ExpectedLayout = Msf.generateLayout();379  ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());380  MSFLayout &L = *ExpectedLayout;381  auto BlocksRef = L.StreamMap[*SN];382  std::vector<uint32_t> Blocks(BlocksRef.begin(), BlocksRef.end());383  EXPECT_EQ(StreamSize, L.StreamSizes[*SN]);384 385  for (uint32_t I = 0; I <= 3; ++I) {386    // Pages from both FPMs are always allocated.387    EXPECT_FALSE(L.FreePageMap.test(2 + I * 4096));388    EXPECT_FALSE(L.FreePageMap.test(1 + I * 4096));389  }390 391  for (uint32_t I = 1; I <= 3; ++I) {392    EXPECT_THAT(Blocks, Not(Contains(1 + I * 4096)));393    EXPECT_THAT(Blocks, Not(Contains(2 + I * 4096)));394  }395}396