blob: ac292a73a8fb7b6586b06bffbc27a443f8d44ab0 [file] [log] [blame]
Zachary Turnerf52a8992016-07-15 20:43:38 +00001//===- 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 "ErrorChecking.h"
11
12#include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h"
13#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h"
14
15#include "gtest/gtest.h"
16
17using namespace llvm;
18using namespace llvm::pdb;
19using namespace llvm::pdb::msf;
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.BlockMapAddr = 1;
35 SB.BlockSize = 4096;
36 SB.NumDirectoryBytes = 0;
37 SB.NumBlocks = 2; // one for the Super Block, one for the directory
38 }
39
40 BumpPtrAllocator Allocator;
41};
42}
43
44TEST_F(MsfBuilderTest, ValidateSuperBlockAccept) {
45 // Test that a known good super block passes validation.
46 SuperBlock SB;
47 initializeSuperBlock(SB);
48
49 EXPECT_NO_ERROR(msf::validateSuperBlock(SB));
50}
51
52TEST_F(MsfBuilderTest, ValidateSuperBlockReject) {
53 // Test that various known problems cause a super block to be rejected.
54 SuperBlock SB;
55 initializeSimpleSuperBlock(SB);
56
57 // Mismatched magic
58 SB.MagicBytes[0] = 8;
59 EXPECT_ERROR(msf::validateSuperBlock(SB));
60 initializeSimpleSuperBlock(SB);
61
62 // Block 0 is reserved for super block, can't be occupied by the block map
63 SB.BlockMapAddr = 0;
64 EXPECT_ERROR(msf::validateSuperBlock(SB));
65 initializeSimpleSuperBlock(SB);
66
67 // Block sizes have to be powers of 2.
68 SB.BlockSize = 3120;
69 EXPECT_ERROR(msf::validateSuperBlock(SB));
70 initializeSimpleSuperBlock(SB);
71
72 // The directory itself has a maximum size.
73 SB.NumDirectoryBytes = SB.BlockSize * SB.BlockSize / 4;
74 EXPECT_NO_ERROR(msf::validateSuperBlock(SB));
75 SB.NumDirectoryBytes = SB.NumDirectoryBytes + 4;
76 EXPECT_ERROR(msf::validateSuperBlock(SB));
77}
78
79TEST_F(MsfBuilderTest, TestUsedBlocksMarkedAsUsed) {
80 // Test that when assigning a stream to a known list of blocks, the blocks
81 // are correctly marked as used after adding, but no other incorrect blocks
82 // are accidentally marked as used.
83
Zachary Turnerb927e022016-07-15 22:17:19 +000084 std::vector<uint32_t> Blocks = {4, 5, 6, 7, 8, 9, 10, 11, 12};
Zachary Turnerf52a8992016-07-15 20:43:38 +000085 // Allocate some extra blocks at the end so we can verify that they're free
86 // after the initialization.
Zachary Turnerb927e022016-07-15 22:17:19 +000087 uint32_t NumBlocks = msf::getMinimumBlockCount() + Blocks.size() + 10;
88 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096, NumBlocks);
Zachary Turnerf52a8992016-07-15 20:43:38 +000089 EXPECT_EXPECTED(ExpectedMsf);
90 auto &Msf = *ExpectedMsf;
91
92 EXPECT_NO_ERROR(Msf.addStream(Blocks.size() * 4096, Blocks));
93
94 for (auto B : Blocks) {
95 EXPECT_FALSE(Msf.isBlockFree(B));
96 }
Zachary Turnerb927e022016-07-15 22:17:19 +000097
98 uint32_t FreeBlockStart = Blocks.back() + 1;
99 for (uint32_t I = FreeBlockStart; I < NumBlocks; ++I) {
Zachary Turnerf52a8992016-07-15 20:43:38 +0000100 EXPECT_TRUE(Msf.isBlockFree(I));
101 }
102}
103
104TEST_F(MsfBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
105 // Test that adding a new stream correctly updates the directory. This only
106 // tests the case where the directory *DOES NOT* grow large enough that it
107 // crosses a Block boundary.
108 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
109 EXPECT_EXPECTED(ExpectedMsf);
110 auto &Msf = *ExpectedMsf;
111
112 auto ExpectedL1 = Msf.build();
113 EXPECT_EXPECTED(ExpectedL1);
114 Layout &L1 = *ExpectedL1;
115
116 auto OldDirBlocks = L1.DirectoryBlocks;
117 EXPECT_EQ(1U, OldDirBlocks.size());
118
119 auto ExpectedMsf2 = MsfBuilder::create(Allocator, 4096);
120 EXPECT_EXPECTED(ExpectedMsf2);
121 auto &Msf2 = *ExpectedMsf2;
122
123 EXPECT_NO_ERROR(Msf2.addStream(4000));
124 EXPECT_EQ(1U, Msf2.getNumStreams());
125 EXPECT_EQ(4000U, Msf2.getStreamSize(0));
126 auto Blocks = Msf2.getStreamBlocks(0);
127 EXPECT_EQ(1U, Blocks.size());
128
129 auto ExpectedL2 = Msf2.build();
130 EXPECT_EXPECTED(ExpectedL2);
131 Layout &L2 = *ExpectedL2;
132 auto NewDirBlocks = L2.DirectoryBlocks;
133 EXPECT_EQ(1U, NewDirBlocks.size());
134}
135
136TEST_F(MsfBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
137 // Test that adding a new stream correctly updates the directory. This only
138 // tests the case where the directory *DOES* grow large enough that it
139 // crosses a Block boundary. This is because the newly added stream occupies
140 // so many Blocks that need to be indexed in the directory that the directory
141 // crosses a Block boundary.
142 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
143 EXPECT_EXPECTED(ExpectedMsf);
144 auto &Msf = *ExpectedMsf;
145
146 EXPECT_NO_ERROR(Msf.addStream(4096 * 4096 / sizeof(uint32_t)));
147
148 auto ExpectedL1 = Msf.build();
149 EXPECT_EXPECTED(ExpectedL1);
150 Layout &L1 = *ExpectedL1;
151 auto DirBlocks = L1.DirectoryBlocks;
152 EXPECT_EQ(2U, DirBlocks.size());
153}
154
155TEST_F(MsfBuilderTest, TestGrowStreamNoBlockIncrease) {
156 // Test growing an existing stream by a value that does not affect the number
157 // of blocks it occupies.
158 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
159 EXPECT_EXPECTED(ExpectedMsf);
160 auto &Msf = *ExpectedMsf;
161
162 EXPECT_NO_ERROR(Msf.addStream(1024));
163 EXPECT_EQ(1024U, Msf.getStreamSize(0));
164 auto OldStreamBlocks = Msf.getStreamBlocks(0);
165 EXPECT_EQ(1U, OldStreamBlocks.size());
166
167 EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
168 EXPECT_EQ(2048U, Msf.getStreamSize(0));
169 auto NewStreamBlocks = Msf.getStreamBlocks(0);
170 EXPECT_EQ(1U, NewStreamBlocks.size());
171
172 EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
173}
174
175TEST_F(MsfBuilderTest, TestGrowStreamWithBlockIncrease) {
176 // Test that growing an existing stream to a value large enough that it causes
177 // the need to allocate new Blocks to the stream correctly updates the
178 // stream's
179 // block list.
180 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
181 EXPECT_EXPECTED(ExpectedMsf);
182 auto &Msf = *ExpectedMsf;
183
184 EXPECT_NO_ERROR(Msf.addStream(2048));
185 EXPECT_EQ(2048U, Msf.getStreamSize(0));
186 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
187 EXPECT_EQ(1U, OldStreamBlocks.size());
188
189 EXPECT_NO_ERROR(Msf.setStreamSize(0, 6144));
190 EXPECT_EQ(6144U, Msf.getStreamSize(0));
191 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
192 EXPECT_EQ(2U, NewStreamBlocks.size());
193
194 EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
195 EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
196}
197
198TEST_F(MsfBuilderTest, TestShrinkStreamNoBlockDecrease) {
199 // Test that shrinking an existing stream by a value that does not affect the
200 // number of Blocks it occupies makes no changes to stream's block list.
201 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
202 EXPECT_EXPECTED(ExpectedMsf);
203 auto &Msf = *ExpectedMsf;
204
205 EXPECT_NO_ERROR(Msf.addStream(2048));
206 EXPECT_EQ(2048U, Msf.getStreamSize(0));
207 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
208 EXPECT_EQ(1U, OldStreamBlocks.size());
209
210 EXPECT_NO_ERROR(Msf.setStreamSize(0, 1024));
211 EXPECT_EQ(1024U, Msf.getStreamSize(0));
212 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
213 EXPECT_EQ(1U, NewStreamBlocks.size());
214
215 EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
216}
217
218TEST_F(MsfBuilderTest, TestShrinkStreamWithBlockDecrease) {
219 // Test that shrinking an existing stream to a value large enough that it
220 // causes the need to deallocate new Blocks to the stream correctly updates
221 // the stream's block list.
222 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
223 EXPECT_EXPECTED(ExpectedMsf);
224 auto &Msf = *ExpectedMsf;
225
226 EXPECT_NO_ERROR(Msf.addStream(6144));
227 EXPECT_EQ(6144U, Msf.getStreamSize(0));
228 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
229 EXPECT_EQ(2U, OldStreamBlocks.size());
230
231 EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
232 EXPECT_EQ(2048U, Msf.getStreamSize(0));
233 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
234 EXPECT_EQ(1U, NewStreamBlocks.size());
235
236 EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
237}
238
239TEST_F(MsfBuilderTest, TestRejectReusedStreamBlock) {
240 // Test that attempting to add a stream and assigning a block that is already
241 // in use by another stream fails.
242 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
243 EXPECT_EXPECTED(ExpectedMsf);
244 auto &Msf = *ExpectedMsf;
245
246 EXPECT_NO_ERROR(Msf.addStream(6144));
247
248 std::vector<uint32_t> Blocks = {2, 3};
249 EXPECT_ERROR(Msf.addStream(6144, Blocks));
250}
251
252TEST_F(MsfBuilderTest, TestBlockCountsWhenAddingStreams) {
253 // Test that when adding multiple streams, the number of used and free Blocks
254 // allocated to the MSF file are as expected.
255 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
256 EXPECT_EXPECTED(ExpectedMsf);
257 auto &Msf = *ExpectedMsf;
258
259 // one for the super block, one for the directory block map
260 uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
Zachary Turnerb927e022016-07-15 22:17:19 +0000261 EXPECT_EQ(msf::getMinimumBlockCount(), NumUsedBlocks);
Zachary Turnerf52a8992016-07-15 20:43:38 +0000262 EXPECT_EQ(0U, Msf.getNumFreeBlocks());
263
264 const uint32_t StreamSizes[] = {4000, 6193, 189723};
265 for (int I = 0; I < 3; ++I) {
266 EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
267 NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
268 EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
269 EXPECT_EQ(0U, Msf.getNumFreeBlocks());
270 }
271}
272
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000273TEST_F(MsfBuilderTest, BuildMsfLayout) {
Zachary Turnerf52a8992016-07-15 20:43:38 +0000274 // Test that we can generate an Msf Layout structure from a valid layout
275 // specification.
276 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
277 EXPECT_EXPECTED(ExpectedMsf);
278 auto &Msf = *ExpectedMsf;
279
280 const uint32_t StreamSizes[] = {4000, 6193, 189723};
Zachary Turnerb927e022016-07-15 22:17:19 +0000281 uint32_t ExpectedNumBlocks = msf::getMinimumBlockCount();
Zachary Turnerf52a8992016-07-15 20:43:38 +0000282 for (int I = 0; I < 3; ++I) {
283 EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
284 ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
285 }
286 ++ExpectedNumBlocks; // The directory itself should use 1 block
287
288 auto ExpectedLayout = Msf.build();
289 EXPECT_EXPECTED(ExpectedLayout);
290 Layout &L = *ExpectedLayout;
291 EXPECT_EQ(4096U, L.SB->BlockSize);
292 EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
293
294 EXPECT_EQ(1U, L.DirectoryBlocks.size());
295
296 EXPECT_EQ(3U, L.StreamMap.size());
297 EXPECT_EQ(3U, L.StreamSizes.size());
298 for (int I = 0; I < 3; ++I) {
299 EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);
300 uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);
301 EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
302 }
303}
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000304
305TEST_F(MsfBuilderTest, UseDirectoryBlockHint) {
Zachary Turnerb927e022016-07-15 22:17:19 +0000306 Expected<MsfBuilder> ExpectedMsf = MsfBuilder::create(
307 Allocator, 4096, msf::getMinimumBlockCount() + 1, false);
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000308 EXPECT_EXPECTED(ExpectedMsf);
309 auto &Msf = *ExpectedMsf;
310
Zachary Turnerb927e022016-07-15 22:17:19 +0000311 uint32_t B = msf::getFirstUnreservedBlock();
312 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1}));
313 EXPECT_NO_ERROR(Msf.addStream(2048, {B + 2}));
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000314
315 auto ExpectedLayout = Msf.build();
316 EXPECT_EXPECTED(ExpectedLayout);
317 Layout &L = *ExpectedLayout;
Zachary Turnerb927e022016-07-15 22:17:19 +0000318 EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000319 EXPECT_EQ(1U, L.DirectoryBlocks.size());
320 EXPECT_EQ(1U, L.StreamMap[0].size());
321
Zachary Turnerb927e022016-07-15 22:17:19 +0000322 EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
323 EXPECT_EQ(B + 2, L.StreamMap[0].front());
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000324}
325
326TEST_F(MsfBuilderTest, DirectoryBlockHintInsufficient) {
Zachary Turnerb927e022016-07-15 22:17:19 +0000327 Expected<MsfBuilder> ExpectedMsf =
328 MsfBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000329 EXPECT_EXPECTED(ExpectedMsf);
330 auto &Msf = *ExpectedMsf;
Zachary Turnerb927e022016-07-15 22:17:19 +0000331 uint32_t B = msf::getFirstUnreservedBlock();
332 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1}));
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000333
334 uint32_t Size = 4096 * 4096 / 4;
335 EXPECT_NO_ERROR(Msf.addStream(Size));
336
337 auto ExpectedLayout = Msf.build();
338 EXPECT_EXPECTED(ExpectedLayout);
339 Layout &L = *ExpectedLayout;
340 EXPECT_EQ(2U, L.DirectoryBlocks.size());
Zachary Turnerb927e022016-07-15 22:17:19 +0000341 EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000342}
343
344TEST_F(MsfBuilderTest, DirectoryBlockHintOverestimated) {
Zachary Turnerb927e022016-07-15 22:17:19 +0000345 Expected<MsfBuilder> ExpectedMsf =
346 MsfBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000347 EXPECT_EXPECTED(ExpectedMsf);
348 auto &Msf = *ExpectedMsf;
349
Zachary Turnerb927e022016-07-15 22:17:19 +0000350 uint32_t B = msf::getFirstUnreservedBlock();
351 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1, B + 2}));
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000352
353 EXPECT_NO_ERROR(Msf.addStream(2048));
354
355 auto ExpectedLayout = Msf.build();
356 EXPECT_EXPECTED(ExpectedLayout);
357 Layout &L = *ExpectedLayout;
358 EXPECT_EQ(1U, L.DirectoryBlocks.size());
Zachary Turnerb927e022016-07-15 22:17:19 +0000359 EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000360}