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