blob: d20f5e52d88bc6d9f696728143875c993ea576e5 [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
84 // Allocate some extra blocks at the end so we can verify that they're free
85 // after the initialization.
86 std::vector<uint32_t> Blocks = {2, 3, 4, 5, 6, 7, 8, 9, 10};
Zachary Turnerfaa554b2016-07-15 22:16:56 +000087 auto ExpectedMsf =
88 MsfBuilder::create(Allocator, 4096, 2 + Blocks.size() + 10);
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 }
97 for (int I = 11; I < 21; ++I) {
98 EXPECT_TRUE(Msf.isBlockFree(I));
99 }
100}
101
102TEST_F(MsfBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
103 // Test that adding a new stream correctly updates the directory. This only
104 // tests the case where the directory *DOES NOT* grow large enough that it
105 // crosses a Block boundary.
106 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
107 EXPECT_EXPECTED(ExpectedMsf);
108 auto &Msf = *ExpectedMsf;
109
110 auto ExpectedL1 = Msf.build();
111 EXPECT_EXPECTED(ExpectedL1);
112 Layout &L1 = *ExpectedL1;
113
114 auto OldDirBlocks = L1.DirectoryBlocks;
115 EXPECT_EQ(1U, OldDirBlocks.size());
116
117 auto ExpectedMsf2 = MsfBuilder::create(Allocator, 4096);
118 EXPECT_EXPECTED(ExpectedMsf2);
119 auto &Msf2 = *ExpectedMsf2;
120
121 EXPECT_NO_ERROR(Msf2.addStream(4000));
122 EXPECT_EQ(1U, Msf2.getNumStreams());
123 EXPECT_EQ(4000U, Msf2.getStreamSize(0));
124 auto Blocks = Msf2.getStreamBlocks(0);
125 EXPECT_EQ(1U, Blocks.size());
126
127 auto ExpectedL2 = Msf2.build();
128 EXPECT_EXPECTED(ExpectedL2);
129 Layout &L2 = *ExpectedL2;
130 auto NewDirBlocks = L2.DirectoryBlocks;
131 EXPECT_EQ(1U, NewDirBlocks.size());
132}
133
134TEST_F(MsfBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
135 // Test that adding a new stream correctly updates the directory. This only
136 // tests the case where the directory *DOES* grow large enough that it
137 // crosses a Block boundary. This is because the newly added stream occupies
138 // so many Blocks that need to be indexed in the directory that the directory
139 // crosses a Block boundary.
140 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
141 EXPECT_EXPECTED(ExpectedMsf);
142 auto &Msf = *ExpectedMsf;
143
144 EXPECT_NO_ERROR(Msf.addStream(4096 * 4096 / sizeof(uint32_t)));
145
146 auto ExpectedL1 = Msf.build();
147 EXPECT_EXPECTED(ExpectedL1);
148 Layout &L1 = *ExpectedL1;
149 auto DirBlocks = L1.DirectoryBlocks;
150 EXPECT_EQ(2U, DirBlocks.size());
151}
152
153TEST_F(MsfBuilderTest, TestGrowStreamNoBlockIncrease) {
154 // Test growing an existing stream by a value that does not affect the number
155 // of blocks it occupies.
156 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
157 EXPECT_EXPECTED(ExpectedMsf);
158 auto &Msf = *ExpectedMsf;
159
160 EXPECT_NO_ERROR(Msf.addStream(1024));
161 EXPECT_EQ(1024U, Msf.getStreamSize(0));
162 auto OldStreamBlocks = Msf.getStreamBlocks(0);
163 EXPECT_EQ(1U, OldStreamBlocks.size());
164
165 EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
166 EXPECT_EQ(2048U, Msf.getStreamSize(0));
167 auto NewStreamBlocks = Msf.getStreamBlocks(0);
168 EXPECT_EQ(1U, NewStreamBlocks.size());
169
170 EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
171}
172
173TEST_F(MsfBuilderTest, TestGrowStreamWithBlockIncrease) {
174 // Test that growing an existing stream to a value large enough that it causes
175 // the need to allocate new Blocks to the stream correctly updates the
176 // stream's
177 // block list.
178 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
179 EXPECT_EXPECTED(ExpectedMsf);
180 auto &Msf = *ExpectedMsf;
181
182 EXPECT_NO_ERROR(Msf.addStream(2048));
183 EXPECT_EQ(2048U, Msf.getStreamSize(0));
184 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
185 EXPECT_EQ(1U, OldStreamBlocks.size());
186
187 EXPECT_NO_ERROR(Msf.setStreamSize(0, 6144));
188 EXPECT_EQ(6144U, Msf.getStreamSize(0));
189 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
190 EXPECT_EQ(2U, NewStreamBlocks.size());
191
192 EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
193 EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
194}
195
196TEST_F(MsfBuilderTest, TestShrinkStreamNoBlockDecrease) {
197 // Test that shrinking an existing stream by a value that does not affect the
198 // number of Blocks it occupies makes no changes to stream's block list.
199 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
200 EXPECT_EXPECTED(ExpectedMsf);
201 auto &Msf = *ExpectedMsf;
202
203 EXPECT_NO_ERROR(Msf.addStream(2048));
204 EXPECT_EQ(2048U, Msf.getStreamSize(0));
205 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
206 EXPECT_EQ(1U, OldStreamBlocks.size());
207
208 EXPECT_NO_ERROR(Msf.setStreamSize(0, 1024));
209 EXPECT_EQ(1024U, Msf.getStreamSize(0));
210 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
211 EXPECT_EQ(1U, NewStreamBlocks.size());
212
213 EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
214}
215
216TEST_F(MsfBuilderTest, TestShrinkStreamWithBlockDecrease) {
217 // Test that shrinking an existing stream to a value large enough that it
218 // causes the need to deallocate new Blocks to the stream correctly updates
219 // the stream's block list.
220 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
221 EXPECT_EXPECTED(ExpectedMsf);
222 auto &Msf = *ExpectedMsf;
223
224 EXPECT_NO_ERROR(Msf.addStream(6144));
225 EXPECT_EQ(6144U, Msf.getStreamSize(0));
226 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
227 EXPECT_EQ(2U, OldStreamBlocks.size());
228
229 EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
230 EXPECT_EQ(2048U, Msf.getStreamSize(0));
231 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
232 EXPECT_EQ(1U, NewStreamBlocks.size());
233
234 EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
235}
236
237TEST_F(MsfBuilderTest, TestRejectReusedStreamBlock) {
238 // Test that attempting to add a stream and assigning a block that is already
239 // in use by another stream fails.
240 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
241 EXPECT_EXPECTED(ExpectedMsf);
242 auto &Msf = *ExpectedMsf;
243
244 EXPECT_NO_ERROR(Msf.addStream(6144));
245
246 std::vector<uint32_t> Blocks = {2, 3};
247 EXPECT_ERROR(Msf.addStream(6144, Blocks));
248}
249
250TEST_F(MsfBuilderTest, TestBlockCountsWhenAddingStreams) {
251 // Test that when adding multiple streams, the number of used and free Blocks
252 // allocated to the MSF file are as expected.
253 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
254 EXPECT_EXPECTED(ExpectedMsf);
255 auto &Msf = *ExpectedMsf;
256
257 // one for the super block, one for the directory block map
258 uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
259 EXPECT_EQ(2U, NumUsedBlocks);
260 EXPECT_EQ(0U, Msf.getNumFreeBlocks());
261
262 const uint32_t StreamSizes[] = {4000, 6193, 189723};
263 for (int I = 0; I < 3; ++I) {
264 EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
265 NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
266 EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
267 EXPECT_EQ(0U, Msf.getNumFreeBlocks());
268 }
269}
270
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000271TEST_F(MsfBuilderTest, BuildMsfLayout) {
Zachary Turnerf52a8992016-07-15 20:43:38 +0000272 // Test that we can generate an Msf Layout structure from a valid layout
273 // specification.
274 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
275 EXPECT_EXPECTED(ExpectedMsf);
276 auto &Msf = *ExpectedMsf;
277
278 const uint32_t StreamSizes[] = {4000, 6193, 189723};
279 uint32_t ExpectedNumBlocks = 2;
280 for (int I = 0; I < 3; ++I) {
281 EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
282 ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
283 }
284 ++ExpectedNumBlocks; // The directory itself should use 1 block
285
286 auto ExpectedLayout = Msf.build();
287 EXPECT_EXPECTED(ExpectedLayout);
288 Layout &L = *ExpectedLayout;
289 EXPECT_EQ(4096U, L.SB->BlockSize);
290 EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
291
292 EXPECT_EQ(1U, L.DirectoryBlocks.size());
293
294 EXPECT_EQ(3U, L.StreamMap.size());
295 EXPECT_EQ(3U, L.StreamSizes.size());
296 for (int I = 0; I < 3; ++I) {
297 EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);
298 uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);
299 EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
300 }
301}
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000302
303TEST_F(MsfBuilderTest, UseDirectoryBlockHint) {
304 Expected<MsfBuilder> ExpectedMsf =
305 MsfBuilder::create(Allocator, 4096, 4, false);
306 EXPECT_EXPECTED(ExpectedMsf);
307 auto &Msf = *ExpectedMsf;
308
309 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2}));
310 EXPECT_NO_ERROR(Msf.addStream(2048, {3}));
311
312 auto ExpectedLayout = Msf.build();
313 EXPECT_EXPECTED(ExpectedLayout);
314 Layout &L = *ExpectedLayout;
315 EXPECT_EQ(4U, L.SB->NumBlocks);
316 EXPECT_EQ(1U, L.DirectoryBlocks.size());
317 EXPECT_EQ(1U, L.StreamMap[0].size());
318
319 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
320 EXPECT_EQ(3U, L.StreamMap[0].front());
321}
322
323TEST_F(MsfBuilderTest, DirectoryBlockHintInsufficient) {
324 Expected<MsfBuilder> ExpectedMsf = MsfBuilder::create(Allocator, 4096, 4);
325 EXPECT_EXPECTED(ExpectedMsf);
326 auto &Msf = *ExpectedMsf;
327
328 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2}));
329
330 uint32_t Size = 4096 * 4096 / 4;
331 EXPECT_NO_ERROR(Msf.addStream(Size));
332
333 auto ExpectedLayout = Msf.build();
334 EXPECT_EXPECTED(ExpectedLayout);
335 Layout &L = *ExpectedLayout;
336 EXPECT_EQ(2U, L.DirectoryBlocks.size());
337 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
338}
339
340TEST_F(MsfBuilderTest, DirectoryBlockHintOverestimated) {
341 Expected<MsfBuilder> ExpectedMsf = MsfBuilder::create(Allocator, 4096, 4);
342 EXPECT_EXPECTED(ExpectedMsf);
343 auto &Msf = *ExpectedMsf;
344
345 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2, 3}));
346
347 EXPECT_NO_ERROR(Msf.addStream(2048));
348
349 auto ExpectedLayout = Msf.build();
350 EXPECT_EXPECTED(ExpectedLayout);
351 Layout &L = *ExpectedLayout;
352 EXPECT_EQ(1U, L.DirectoryBlocks.size());
353 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
354}