llvm.org GIT mirror llvm / 9b30e73
[pdb] Teach MsfBuilder and other classes about the Free Page Map. Block 1 and 2 of an MSF file are bit vectors that represent the list of blocks allocated and free in the file. We had been using these blocks to write stream data and other data, so we mark them as the free page map now. We don't yet serialize these pages to the disk, but at least we make a note of what it is, and avoid writing random data to them. Doing this also necessitated cleaning up some of the tests to be more general and hardcode fewer values, which is nice. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275629 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 4 years ago
12 changed file(s) with 70 addition(s) and 49 deletion(s). Raw diff Collapse all Expand all
6363 /// when editing a PDB and you want the layout to be as stable as possible.
6464 Error setBlockMapAddr(uint32_t Addr);
6565 Error setDirectoryBlocksHint(ArrayRef DirBlocks);
66 void setUnknown0(uint32_t Unk0);
66 void setFreePageMap(uint32_t Fpm);
6767 void setUnknown1(uint32_t Unk1);
6868
6969 /// Add a stream to the MSF file with the given size, occupying the given
125125 BumpPtrAllocator &Allocator;
126126
127127 bool IsGrowable;
128 uint32_t Unknown0;
128 uint32_t FreePageMap;
129129 uint32_t Unknown1;
130130 uint32_t BlockSize;
131131 uint32_t MininumBlocks;
3434 // These elements are referred to as blocks. The size of a block may vary
3535 // from system to system.
3636 support::ulittle32_t BlockSize;
37 // This field's purpose is not yet known.
38 support::ulittle32_t Unknown0;
37 // The index of the free block map.
38 support::ulittle32_t FreeBlockMapBlock;
3939 // This contains the number of blocks resident in the file system. In
4040 // practice, NumBlocks * BlockSize is equivalent to the size of the PDB
4141 // file.
6666 return false;
6767 }
6868
69 // Super Block, Fpm0, Fpm1, and Block Map
70 inline uint32_t getMinimumBlockCount() { return 4; }
71
72 // Super Block, Fpm0, and Fpm1 are reserved. The Block Map, although required
73 // need not be at block 3.
74 inline uint32_t getFirstUnreservedBlock() { return 3; }
75
6976 inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
7077 return alignTo(NumBytes, BlockSize) / BlockSize;
7178 }
4444 explicit PDBFile(std::unique_ptr PdbFileBuffer);
4545 ~PDBFile() override;
4646
47 uint32_t getUnknown0() const;
47 uint32_t getFreeBlockMapBlock() const;
4848 uint32_t getUnknown1() const;
4949
5050 uint32_t getBlockSize() const override;
1616
1717 namespace {
1818 const uint32_t kSuperBlockBlock = 0;
19 const uint32_t kDefaultBlockMapAddr = 1;
19 const uint32_t kFreePageMap0Block = 1;
20 const uint32_t kFreePageMap1Block = 2;
21 const uint32_t kNumReservedPages = 3;
22
23 const uint32_t kDefaultBlockMapAddr = kNumReservedPages;
2024 }
2125
2226 MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow,
2327 BumpPtrAllocator &Allocator)
2428 : Allocator(Allocator), IsGrowable(CanGrow), BlockSize(BlockSize),
2529 MininumBlocks(MinBlockCount), BlockMapAddr(kDefaultBlockMapAddr),
26 FreeBlocks(std::max(MinBlockCount, 2U), true) {
30 FreeBlocks(MinBlockCount, true) {
2731 FreeBlocks[kSuperBlockBlock] = false;
32 FreeBlocks[kFreePageMap0Block] = false;
33 FreeBlocks[kFreePageMap1Block] = false;
2834 FreeBlocks[BlockMapAddr] = false;
2935 }
3036
3541 return make_error(raw_error_code::unspecified,
3642 "The requested block size is unsupported");
3743
38 return MsfBuilder(BlockSize, MinBlockCount, CanGrow, Allocator);
44 return MsfBuilder(BlockSize,
45 std::max(MinBlockCount, msf::getMinimumBlockCount()),
46 CanGrow, Allocator);
3947 }
4048
4149 Error MsfBuilder::setBlockMapAddr(uint32_t Addr) {
5866 return Error::success();
5967 }
6068
61 void MsfBuilder::setUnknown0(uint32_t Unk0) { Unknown0 = Unk0; }
69 void MsfBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; }
6270
6371 void MsfBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; }
6472
216224 L.SB->BlockMapAddr = BlockMapAddr;
217225 L.SB->BlockSize = BlockSize;
218226 L.SB->NumDirectoryBytes = computeDirectoryByteSize();
219 L.SB->Unknown0 = Unknown0;
227 L.SB->FreeBlockMapBlock = FreePageMap;
220228 L.SB->Unknown1 = Unknown1;
221229
222230 uint32_t NumDirectoryBlocks =
4141
4242 uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; }
4343
44 uint32_t PDBFile::getUnknown0() const { return SB->Unknown0; }
44 uint32_t PDBFile::getFreeBlockMapBlock() const { return SB->FreeBlockMapBlock; }
4545
4646 uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; }
4747
3636 auto &MsfResult = *ExpectedMsf;
3737 if (auto EC = MsfResult.setBlockMapAddr(Super.BlockMapAddr))
3838 return EC;
39 MsfResult.setUnknown0(Super.Unknown0);
40 MsfResult.setUnknown1(Super.Unknown1);
4139 Msf = llvm::make_unique(std::move(MsfResult));
40 Msf->setFreePageMap(Super.FreeBlockMapBlock);
41 Msf->setUnknown1(Super.Unknown1);
4242 return Error::success();
4343 }
4444
99
1010 ; EMPTY: FileHeaders {
1111 ; EMPTY-NEXT: BlockSize: 4096
12 ; EMPTY-NEXT: Unknown0: 2
12 ; EMPTY-NEXT: FreeBlockMap: 2
1313 ; EMPTY-NEXT: NumBlocks: 25
1414 ; EMPTY-NEXT: NumDirectoryBytes: 136
1515 ; EMPTY-NEXT: Unknown1: 0
944944
945945 ; ALL: FileHeaders {
946946 ; ALL: BlockSize: 4096
947 ; ALL: Unknown0: 2
947 ; ALL: FreeBlockMap: 2
948948 ; ALL: NumBlocks: 25
949949 ; ALL: NumDirectoryBytes: 136
950950 ; ALL: Unknown1: 0
16591659
16601660 ; BIG: FileHeaders {
16611661 ; BIG-NEXT: BlockSize: 4096
1662 ; BIG-NEXT: Unknown0: 2
1662 ; BIG-NEXT: FreeBlockMap: 2
16631663 ; BIG-NEXT: NumBlocks: 99
16641664 ; BIG-NEXT: NumDirectoryBytes: 616
16651665 ; BIG-NEXT: Unknown1: 0
66 ; YAML-NEXT: MSF:
77 ; YAML-NEXT: SuperBlock:
88 ; YAML-NEXT: BlockSize: 4096
9 ; YAML-NEXT: Unknown0: 2
9 ; YAML-NEXT: FreeBlockMap: 2
1010 ; YAML-NEXT: NumBlocks: 25
1111 ; YAML-NEXT: NumDirectoryBytes: 136
1212 ; YAML-NEXT: Unknown1: 0
9494
9595 DictScope D(P, "FileHeaders");
9696 P.printNumber("BlockSize", File.getBlockSize());
97 P.printNumber("Unknown0", File.getUnknown0());
97 P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock());
9898 P.printNumber("NumBlocks", File.getBlockCount());
9999 P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes());
100100 P.printNumber("Unknown1", File.getUnknown1());
125125 }
126126
127127 IO.mapRequired("BlockSize", SB.BlockSize);
128 IO.mapRequired("Unknown0", SB.Unknown0);
128 IO.mapRequired("FreeBlockMap", SB.FreeBlockMapBlock);
129129 IO.mapRequired("NumBlocks", SB.NumBlocks);
130130 IO.mapRequired("NumDirectoryBytes", SB.NumDirectoryBytes);
131131 IO.mapRequired("Unknown1", SB.Unknown1);
5959 Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes();
6060 Obj.Headers->NumStreams =
6161 opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0;
62 Obj.Headers->SuperBlock.Unknown0 = File.getUnknown0();
62 Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock();
6363 Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1();
6464 Obj.Headers->FileSize = File.getFileSize();
6565
8080 // are correctly marked as used after adding, but no other incorrect blocks
8181 // are accidentally marked as used.
8282
83 std::vector Blocks = {4, 5, 6, 7, 8, 9, 10, 11, 12};
8384 // Allocate some extra blocks at the end so we can verify that they're free
8485 // after the initialization.
85 std::vector Blocks = {2, 3, 4, 5, 6, 7, 8, 9, 10};
86 auto ExpectedMsf =
87 MsfBuilder::create(Allocator, 4096, 2 + Blocks.size() + 10);
86 uint32_t NumBlocks = msf::getMinimumBlockCount() + Blocks.size() + 10;
87 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096, NumBlocks);
8888 EXPECT_EXPECTED(ExpectedMsf);
8989 auto &Msf = *ExpectedMsf;
9090
9393 for (auto B : Blocks) {
9494 EXPECT_FALSE(Msf.isBlockFree(B));
9595 }
96 for (int I = 11; I < 21; ++I) {
96
97 uint32_t FreeBlockStart = Blocks.back() + 1;
98 for (uint32_t I = FreeBlockStart; I < NumBlocks; ++I) {
9799 EXPECT_TRUE(Msf.isBlockFree(I));
98100 }
99101 }
255257
256258 // one for the super block, one for the directory block map
257259 uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
258 EXPECT_EQ(2U, NumUsedBlocks);
260 EXPECT_EQ(msf::getMinimumBlockCount(), NumUsedBlocks);
259261 EXPECT_EQ(0U, Msf.getNumFreeBlocks());
260262
261263 const uint32_t StreamSizes[] = {4000, 6193, 189723};
275277 auto &Msf = *ExpectedMsf;
276278
277279 const uint32_t StreamSizes[] = {4000, 6193, 189723};
278 uint32_t ExpectedNumBlocks = 2;
280 uint32_t ExpectedNumBlocks = msf::getMinimumBlockCount();
279281 for (int I = 0; I < 3; ++I) {
280282 EXPECT_NO_ERROR(Msf.addStream(StreamSizes[I]));
281283 ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
300302 }
301303
302304 TEST_F(MsfBuilderTest, UseDirectoryBlockHint) {
303 Expected ExpectedMsf =
304 MsfBuilder::create(Allocator, 4096, 4, false);
305 EXPECT_EXPECTED(ExpectedMsf);
306 auto &Msf = *ExpectedMsf;
307
308 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2}));
309 EXPECT_NO_ERROR(Msf.addStream(2048, {3}));
305 Expected ExpectedMsf = MsfBuilder::create(
306 Allocator, 4096, msf::getMinimumBlockCount() + 1, false);
307 EXPECT_EXPECTED(ExpectedMsf);
308 auto &Msf = *ExpectedMsf;
309
310 uint32_t B = msf::getFirstUnreservedBlock();
311 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1}));
312 EXPECT_NO_ERROR(Msf.addStream(2048, {B + 2}));
310313
311314 auto ExpectedLayout = Msf.build();
312315 EXPECT_EXPECTED(ExpectedLayout);
313316 Layout &L = *ExpectedLayout;
314 EXPECT_EQ(4U, L.SB->NumBlocks);
317 EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);
315318 EXPECT_EQ(1U, L.DirectoryBlocks.size());
316319 EXPECT_EQ(1U, L.StreamMap[0].size());
317320
318 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
319 EXPECT_EQ(3U, L.StreamMap[0].front());
321 EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
322 EXPECT_EQ(B + 2, L.StreamMap[0].front());
320323 }
321324
322325 TEST_F(MsfBuilderTest, DirectoryBlockHintInsufficient) {
323 Expected ExpectedMsf = MsfBuilder::create(Allocator, 4096, 4);
324 EXPECT_EXPECTED(ExpectedMsf);
325 auto &Msf = *ExpectedMsf;
326
327 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2}));
326 Expected ExpectedMsf =
327 MsfBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
328 EXPECT_EXPECTED(ExpectedMsf);
329 auto &Msf = *ExpectedMsf;
330 uint32_t B = msf::getFirstUnreservedBlock();
331 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1}));
328332
329333 uint32_t Size = 4096 * 4096 / 4;
330334 EXPECT_NO_ERROR(Msf.addStream(Size));
333337 EXPECT_EXPECTED(ExpectedLayout);
334338 Layout &L = *ExpectedLayout;
335339 EXPECT_EQ(2U, L.DirectoryBlocks.size());
336 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
340 EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
337341 }
338342
339343 TEST_F(MsfBuilderTest, DirectoryBlockHintOverestimated) {
340 Expected ExpectedMsf = MsfBuilder::create(Allocator, 4096, 4);
341 EXPECT_EXPECTED(ExpectedMsf);
342 auto &Msf = *ExpectedMsf;
343
344 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2, 3}));
344 Expected ExpectedMsf =
345 MsfBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
346 EXPECT_EXPECTED(ExpectedMsf);
347 auto &Msf = *ExpectedMsf;
348
349 uint32_t B = msf::getFirstUnreservedBlock();
350 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({B + 1, B + 2}));
345351
346352 EXPECT_NO_ERROR(Msf.addStream(2048));
347353
349355 EXPECT_EXPECTED(ExpectedLayout);
350356 Layout &L = *ExpectedLayout;
351357 EXPECT_EQ(1U, L.DirectoryBlocks.size());
352 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
353 }
358 EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
359 }