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:
initializeSimpleSuperBlock(msf::SuperBlock & SB)25 void initializeSimpleSuperBlock(msf::SuperBlock &SB) {
26 initializeSuperBlock(SB);
27 SB.NumBlocks = 1000;
28 SB.NumDirectoryBytes = 8192;
29 }
30
initializeSuperBlock(msf::SuperBlock & SB)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
TEST_F(MSFBuilderTest,ValidateSuperBlockAccept)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
TEST_F(MSFBuilderTest,ValidateSuperBlockReject)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
TEST_F(MSFBuilderTest,TestUsedBlocksMarkedAsUsed)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
TEST_F(MSFBuilderTest,TestAddStreamNoDirectoryBlockIncrease)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
TEST_F(MSFBuilderTest,TestAddStreamWithDirectoryBlockIncrease)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
TEST_F(MSFBuilderTest,TestGrowStreamNoBlockIncrease)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
TEST_F(MSFBuilderTest,TestGrowStreamWithBlockIncrease)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
TEST_F(MSFBuilderTest,TestShrinkStreamNoBlockDecrease)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
TEST_F(MSFBuilderTest,TestShrinkStreamWithBlockDecrease)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
TEST_F(MSFBuilderTest,TestRejectReusedStreamBlock)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
TEST_F(MSFBuilderTest,TestBlockCountsWhenAddingStreams)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
TEST_F(MSFBuilderTest,BuildMsfLayout)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
TEST_F(MSFBuilderTest,UseDirectoryBlockHint)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
TEST_F(MSFBuilderTest,DirectoryBlockHintInsufficient)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
TEST_F(MSFBuilderTest,DirectoryBlockHintOverestimated)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
TEST_F(MSFBuilderTest,StreamDoesntUseFpmBlocks)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