blob: f0b48ec1577373c61b07ca5ec3e3a40640a72fcd [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};
87 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096, Blocks.size() + 10);
88 EXPECT_EXPECTED(ExpectedMsf);
89 auto &Msf = *ExpectedMsf;
90
91 EXPECT_NO_ERROR(Msf.addStream(Blocks.size() * 4096, Blocks));
92
93 for (auto B : Blocks) {
94 EXPECT_FALSE(Msf.isBlockFree(B));
95 }
96 for (int I = 11; I < 21; ++I) {
97 EXPECT_TRUE(Msf.isBlockFree(I));
98 }
99}
100
101TEST_F(MsfBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
102 // Test that adding a new stream correctly updates the directory. This only
103 // tests the case where the directory *DOES NOT* grow large enough that it
104 // crosses a Block boundary.
105 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
106 EXPECT_EXPECTED(ExpectedMsf);
107 auto &Msf = *ExpectedMsf;
108
109 auto ExpectedL1 = Msf.build();
110 EXPECT_EXPECTED(ExpectedL1);
111 Layout &L1 = *ExpectedL1;
112
113 auto OldDirBlocks = L1.DirectoryBlocks;
114 EXPECT_EQ(1U, OldDirBlocks.size());
115
116 auto ExpectedMsf2 = MsfBuilder::create(Allocator, 4096);
117 EXPECT_EXPECTED(ExpectedMsf2);
118 auto &Msf2 = *ExpectedMsf2;
119
120 EXPECT_NO_ERROR(Msf2.addStream(4000));
121 EXPECT_EQ(1U, Msf2.getNumStreams());
122 EXPECT_EQ(4000U, Msf2.getStreamSize(0));
123 auto Blocks = Msf2.getStreamBlocks(0);
124 EXPECT_EQ(1U, Blocks.size());
125
126 auto ExpectedL2 = Msf2.build();
127 EXPECT_EXPECTED(ExpectedL2);
128 Layout &L2 = *ExpectedL2;
129 auto NewDirBlocks = L2.DirectoryBlocks;
130 EXPECT_EQ(1U, NewDirBlocks.size());
131}
132
133TEST_F(MsfBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
134 // Test that adding a new stream correctly updates the directory. This only
135 // tests the case where the directory *DOES* grow large enough that it
136 // crosses a Block boundary. This is because the newly added stream occupies
137 // so many Blocks that need to be indexed in the directory that the directory
138 // crosses a Block boundary.
139 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
140 EXPECT_EXPECTED(ExpectedMsf);
141 auto &Msf = *ExpectedMsf;
142
143 EXPECT_NO_ERROR(Msf.addStream(4096 * 4096 / sizeof(uint32_t)));
144
145 auto ExpectedL1 = Msf.build();
146 EXPECT_EXPECTED(ExpectedL1);
147 Layout &L1 = *ExpectedL1;
148 auto DirBlocks = L1.DirectoryBlocks;
149 EXPECT_EQ(2U, DirBlocks.size());
150}
151
152TEST_F(MsfBuilderTest, TestGrowStreamNoBlockIncrease) {
153 // Test growing an existing stream by a value that does not affect the number
154 // of blocks it occupies.
155 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
156 EXPECT_EXPECTED(ExpectedMsf);
157 auto &Msf = *ExpectedMsf;
158
159 EXPECT_NO_ERROR(Msf.addStream(1024));
160 EXPECT_EQ(1024U, Msf.getStreamSize(0));
161 auto OldStreamBlocks = Msf.getStreamBlocks(0);
162 EXPECT_EQ(1U, OldStreamBlocks.size());
163
164 EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
165 EXPECT_EQ(2048U, Msf.getStreamSize(0));
166 auto NewStreamBlocks = Msf.getStreamBlocks(0);
167 EXPECT_EQ(1U, NewStreamBlocks.size());
168
169 EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
170}
171
172TEST_F(MsfBuilderTest, TestGrowStreamWithBlockIncrease) {
173 // Test that growing an existing stream to a value large enough that it causes
174 // the need to allocate new Blocks to the stream correctly updates the
175 // stream's
176 // block list.
177 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
178 EXPECT_EXPECTED(ExpectedMsf);
179 auto &Msf = *ExpectedMsf;
180
181 EXPECT_NO_ERROR(Msf.addStream(2048));
182 EXPECT_EQ(2048U, Msf.getStreamSize(0));
183 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
184 EXPECT_EQ(1U, OldStreamBlocks.size());
185
186 EXPECT_NO_ERROR(Msf.setStreamSize(0, 6144));
187 EXPECT_EQ(6144U, Msf.getStreamSize(0));
188 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
189 EXPECT_EQ(2U, NewStreamBlocks.size());
190
191 EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
192 EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
193}
194
195TEST_F(MsfBuilderTest, TestShrinkStreamNoBlockDecrease) {
196 // Test that shrinking an existing stream by a value that does not affect the
197 // number of Blocks it occupies makes no changes to stream's block list.
198 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
199 EXPECT_EXPECTED(ExpectedMsf);
200 auto &Msf = *ExpectedMsf;
201
202 EXPECT_NO_ERROR(Msf.addStream(2048));
203 EXPECT_EQ(2048U, Msf.getStreamSize(0));
204 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
205 EXPECT_EQ(1U, OldStreamBlocks.size());
206
207 EXPECT_NO_ERROR(Msf.setStreamSize(0, 1024));
208 EXPECT_EQ(1024U, Msf.getStreamSize(0));
209 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
210 EXPECT_EQ(1U, NewStreamBlocks.size());
211
212 EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
213}
214
215TEST_F(MsfBuilderTest, TestShrinkStreamWithBlockDecrease) {
216 // Test that shrinking an existing stream to a value large enough that it
217 // causes the need to deallocate new Blocks to the stream correctly updates
218 // the stream's block list.
219 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
220 EXPECT_EXPECTED(ExpectedMsf);
221 auto &Msf = *ExpectedMsf;
222
223 EXPECT_NO_ERROR(Msf.addStream(6144));
224 EXPECT_EQ(6144U, Msf.getStreamSize(0));
225 std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
226 EXPECT_EQ(2U, OldStreamBlocks.size());
227
228 EXPECT_NO_ERROR(Msf.setStreamSize(0, 2048));
229 EXPECT_EQ(2048U, Msf.getStreamSize(0));
230 std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
231 EXPECT_EQ(1U, NewStreamBlocks.size());
232
233 EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
234}
235
236TEST_F(MsfBuilderTest, TestRejectReusedStreamBlock) {
237 // Test that attempting to add a stream and assigning a block that is already
238 // in use by another stream fails.
239 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
240 EXPECT_EXPECTED(ExpectedMsf);
241 auto &Msf = *ExpectedMsf;
242
243 EXPECT_NO_ERROR(Msf.addStream(6144));
244
245 std::vector<uint32_t> Blocks = {2, 3};
246 EXPECT_ERROR(Msf.addStream(6144, Blocks));
247}
248
249TEST_F(MsfBuilderTest, TestBlockCountsWhenAddingStreams) {
250 // Test that when adding multiple streams, the number of used and free Blocks
251 // allocated to the MSF file are as expected.
252 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
253 EXPECT_EXPECTED(ExpectedMsf);
254 auto &Msf = *ExpectedMsf;
255
256 // one for the super block, one for the directory block map
257 uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
258 EXPECT_EQ(2U, NumUsedBlocks);
259 EXPECT_EQ(0U, Msf.getNumFreeBlocks());
260
261 const uint32_t StreamSizes[] = {4000, 6193, 189723};
262 for (int I = 0; I < 3; ++I) {
263 EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
264 NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
265 EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
266 EXPECT_EQ(0U, Msf.getNumFreeBlocks());
267 }
268}
269
270TEST_F(MsfBuilderTest, TestBuildMsfLayout) {
271 // Test that we can generate an Msf Layout structure from a valid layout
272 // specification.
273 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
274 EXPECT_EXPECTED(ExpectedMsf);
275 auto &Msf = *ExpectedMsf;
276
277 const uint32_t StreamSizes[] = {4000, 6193, 189723};
278 uint32_t ExpectedNumBlocks = 2;
279 for (int I = 0; I < 3; ++I) {
280 EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
281 ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
282 }
283 ++ExpectedNumBlocks; // The directory itself should use 1 block
284
285 auto ExpectedLayout = Msf.build();
286 EXPECT_EXPECTED(ExpectedLayout);
287 Layout &L = *ExpectedLayout;
288 EXPECT_EQ(4096U, L.SB->BlockSize);
289 EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
290
291 EXPECT_EQ(1U, L.DirectoryBlocks.size());
292
293 EXPECT_EQ(3U, L.StreamMap.size());
294 EXPECT_EQ(3U, L.StreamSizes.size());
295 for (int I = 0; I < 3; ++I) {
296 EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);
297 uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);
298 EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
299 }
300}