Index: lib/DebugInfo/MSF/MSFBuilder.cpp =================================================================== --- lib/DebugInfo/MSF/MSFBuilder.cpp +++ lib/DebugInfo/MSF/MSFBuilder.cpp @@ -253,6 +253,22 @@ // grow. SB->NumBlocks = FreeBlocks.size(); + // Allocate discontiguous free page map blocks. If one page is too + // small to store the entire FPM, two or more pages are allocated + // for the FPM. + uint32_t NumFPMs = alignTo(FreeBlocks.size(), BlockSize) / BlockSize; + for (uint32_t I = 0; I != NumFPMs; ++I) { + FreeBlocks[I * BlockSize + kFreePageMap0Block] = false; + FreeBlocks[I * BlockSize + kFreePageMap1Block] = false; + } + + // Copy free page map. Note that on-disk FPM is slightly different from + // in-memory FPM since the pages for stream 0 are marked unused on-disk. + // We need to do that for compatibility. + L.FreePageMap = FreeBlocks; + for (uint32_t BlockNumber : StreamData[0].second) + L.FreePageMap[BlockNumber] = false; + ulittle32_t *DirBlocks = Allocator.Allocate(NumDirectoryBlocks); std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks, DirBlocks); Index: lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp +++ lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp @@ -113,6 +113,25 @@ if (auto EC = Writer.writeObject(*Layout.SB)) return EC; + + // Write free page map. + uint32_t BlockSize = Layout.SB->BlockSize; + BitVector FPM = Layout.FreePageMap; + FPM.resize(alignTo(FPM.size(), BlockSize), true); + uint32_t NumFPMBlocks = FPM.size() / BlockSize; + for (uint32_t I = 0; I != NumFPMBlocks; ++I) { + std::vector Buf(Layout.SB->BlockSize); + for (uint32_t J = 0; J != BlockSize; ++J) + if (FPM[I * BlockSize + J]) + Buf[J / 8] |= 1 << (J % 8); + + uint32_t PageNum = I * BlockSize + Layout.SB->FreeBlockMapBlock; + Writer.setOffset(PageNum * BlockSize); + if (auto EC = Writer.writeArray(ArrayRef(Buf))) + return EC; + } + + // Write block map. uint32_t BlockMapOffset = msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); Writer.setOffset(BlockMapOffset); @@ -145,4 +164,4 @@ } return Buffer.commit(); -} \ No newline at end of file +} Index: test/DebugInfo/PDB/pdbdump-fpm.test =================================================================== --- /dev/null +++ test/DebugInfo/PDB/pdbdump-fpm.test @@ -0,0 +1,21 @@ +# RUN: llvm-pdbdump yaml2pdb -pdb=%t.pdb %s +# RUN: llvm-pdbdump raw -page-stats %t.pdb | FileCheck %s + +# CHECK: Multiply Used Pages: [] +# CHECK: Use After Free Pages: [] + +MSF: + SuperBlock: + BlockSize: 1024 + FreeBlockMap: 2 + NumBlocks: 2000 + NumDirectoryBytes: 136 + Unknown1: 0 + BlockMapAddr: 24 + NumDirectoryBlocks: 1 + DirectoryBlocks: [ 23 ] + NumStreams: 1 + FileSize: 2048000 +StreamSizes: [ 40 ] +StreamMap: + - Stream: [ 8 ] Index: test/DebugInfo/PDB/pdbdump-readwrite.test =================================================================== --- test/DebugInfo/PDB/pdbdump-readwrite.test +++ test/DebugInfo/PDB/pdbdump-readwrite.test @@ -3,36 +3,51 @@ RUN: %p/Inputs/empty.pdb > %t.1 RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1 -RUN: llvm-pdbdump raw -headers %p/Inputs/empty.pdb | FileCheck %s -RUN: llvm-pdbdump raw -headers %t.2 | FileCheck %s +RUN: llvm-pdbdump raw -headers %p/Inputs/empty.pdb | FileCheck -check-prefix=HDR %s +RUN: llvm-pdbdump raw -headers %t.2 | FileCheck -check-prefix=HDR %s -CHECK: FileHeaders { -CHECK-NEXT: BlockSize: 4096 -CHECK-NEXT: FreeBlockMap: 2 -CHECK-NEXT: NumBlocks: 25 -CHECK-NEXT: NumDirectoryBytes: 136 -CHECK-NEXT: Unknown1: 0 -CHECK-NEXT: BlockMapAddr: 24 -CHECK-NEXT: NumDirectoryBlocks: 1 -CHECK-NEXT: DirectoryBlocks: [23] -CHECK-NEXT: NumStreams: 17 -CHECK-NEXT: } -CHECK-NEXT: PDB Stream { -CHECK-NEXT: Version: 20000404 -CHECK-NEXT: Signature: 0x54E507E2 -CHECK-NEXT: Age: 1 -CHECK-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} -CHECK-NEXT: } -CHECK-NEXT: DBI Stream { -CHECK-NEXT: Dbi Version: 19990903 -CHECK-NEXT: Age: 1 -CHECK-NEXT: Incremental Linking: Yes -CHECK-NEXT: Has CTypes: No -CHECK-NEXT: Is Stripped: No -CHECK-NEXT: Machine Type: x86 -CHECK-NEXT: Symbol Record Stream Index: -CHECK-NEXT: Public Symbol Stream Index: -CHECK-NEXT: Global Symbol Stream Index: -CHECK-NEXT: Toolchain Version: 12.0 -CHECK-NEXT: mspdb120.dll version: 12.0.31101 -CHECK-NEXT: } +HDR: FileHeaders { +HDR-NEXT: BlockSize: 4096 +HDR-NEXT: FreeBlockMap: 2 +HDR-NEXT: NumBlocks: 25 +HDR-NEXT: NumDirectoryBytes: 136 +HDR-NEXT: Unknown1: 0 +HDR-NEXT: BlockMapAddr: 24 +HDR-NEXT: NumDirectoryBlocks: 1 +HDR-NEXT: DirectoryBlocks: [23] +HDR-NEXT: NumStreams: 17 +HDR-NEXT: } +HDR-NEXT: PDB Stream { +HDR-NEXT: Version: 20000404 +HDR-NEXT: Signature: 0x54E507E2 +HDR-NEXT: Age: 1 +HDR-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0} +HDR-NEXT: } +HDR-NEXT: DBI Stream { +HDR-NEXT: Dbi Version: 19990903 +HDR-NEXT: Age: 1 +HDR-NEXT: Incremental Linking: Yes +HDR-NEXT: Has CTypes: No +HDR-NEXT: Is Stripped: No +HDR-NEXT: Machine Type: x86 +HDR-NEXT: Symbol Record Stream Index: +HDR-NEXT: Public Symbol Stream Index: +HDR-NEXT: Global Symbol Stream Index: +HDR-NEXT: Toolchain Version: 12.0 +HDR-NEXT: mspdb120.dll version: 12.0.31101 +HDR-NEXT: } + +RUN: llvm-pdbdump raw -page-stats %p/Inputs/empty.pdb | FileCheck -check-prefix=FPM1 %s +RUN: llvm-pdbdump raw -page-stats %t.2 | FileCheck -check-prefix=FPM2 %s + +FPM1: Msf Free Pages: [3, 4, 5, 8, 9] +FPM1-NEXT: Orphaned Pages: [] +FPM1-NEXT: Multiply Used Pages: [] +FPM1-NEXT: Use After Free Pages: [] + +;; We are not able to correctly restore stream 0. +;; That's why we get a different result. +FPM2: Msf Free Pages: [3, 4, 5, 9] +FPM2-NEXT: Orphaned Pages: [8] +FPM2-NEXT: Multiply Used Pages: [] +FPM2-NEXT: Use After Free Pages: []