summaryrefslogtreecommitdiffstats
path: root/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2016-08-01 21:19:45 +0000
committerZachary Turner <zturner@google.com>2016-08-01 21:19:45 +0000
commitd3c7b8e303e96fae3ab0c3fc6a42f7f8b87a17e4 (patch)
tree90e2fca0d8963e50c19084b3bb7551035750aaac /llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp
parente594277683e686a30fe63b90ccd43e5cdebe24c3 (diff)
downloadbcm5719-llvm-d3c7b8e303e96fae3ab0c3fc6a42f7f8b87a17e4.tar.gz
bcm5719-llvm-d3c7b8e303e96fae3ab0c3fc6a42f7f8b87a17e4.zip
[msf] Teach LLVM to parse a split Fpm.
The FPM is split at regular intervals across the MSF file, as the MS code suggests. It turns out that the value of the interval is precisely the block size. If the block size is 4096, then there are two Fpm pages every 4096 blocks. So here we teach the PDBFile class to parse a split FPM, and also add more options when dumping the FPM to display some additional information such as orphaned pages (pages which the FPM says are allocated, but which nothing appears to use), use after free pages (pages which the FPM says are not allocated, but which are referenced by a stream), and multiple use pages (pages which the FPM says are allocated but are used more than once). Reviewed By: ruiu Differential Revision: https://reviews.llvm.org/D23022 llvm-svn: 277388
Diffstat (limited to 'llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp')
-rw-r--r--llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp43
1 files changed, 35 insertions, 8 deletions
diff --git a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp
index 533242fdb81..8520408ebd3 100644
--- a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp
+++ b/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp
@@ -121,14 +121,41 @@ Error PDBFile::parseFileHeaders() {
ContainerLayout.SB = SB;
// Initialize Free Page Map.
- ContainerLayout.FreePageMap.resize(getBlockSize() * 8);
- uint64_t FPMOffset = SB->FreeBlockMapBlock * getBlockSize();
- ArrayRef<uint8_t> FPMBlock;
- if (auto EC = Buffer->readBytes(FPMOffset, getBlockSize(), FPMBlock))
- return EC;
- for (uint32_t I = 0, E = getBlockSize() * 8; I != E; ++I)
- if (FPMBlock[I / 8] & (1 << (I % 8)))
- ContainerLayout.FreePageMap[I] = true;
+ ContainerLayout.FreePageMap.resize(SB->NumBlocks);
+ ArrayRef<uint8_t> FpmBytes;
+ // The Fpm exists either at block 1 or block 2 of the MSF. However, this
+ // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
+ // thusly an equal number of total blocks in the file. For a block size
+ // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
+ // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so
+ // the Fpm is split across the file at `getBlockSize()` intervals. As a
+ // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
+ // for any non-negative integer k is an Fpm block. In theory, we only really
+ // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
+ // current versions of the MSF format already expect the Fpm to be arranged
+ // at getBlockSize() intervals, so we have to be compatible.
+ // See the function fpmPn() for more information:
+ // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
+
+ uint32_t BlocksPerSection = getBlockSize();
+ uint64_t FpmBlockOffset = SB->FreeBlockMapBlock;
+ uint32_t BlocksRemaining = getBlockCount();
+ for (uint32_t SI = 0; BlocksRemaining > 0; ++SI) {
+ uint32_t FpmFileOffset = FpmBlockOffset * getBlockSize();
+
+ if (auto EC = Buffer->readBytes(FpmFileOffset, getBlockSize(), FpmBytes))
+ return EC;
+
+ uint32_t BlocksThisSection = std::min(BlocksRemaining, BlocksPerSection);
+ for (uint32_t I = 0; I < BlocksThisSection; ++I) {
+ uint32_t BI = I + BlocksPerSection * SI;
+
+ if (FpmBytes[I / 8] & (1 << (I % 8)))
+ ContainerLayout.FreePageMap[BI] = true;
+ }
+ BlocksRemaining -= BlocksThisSection;
+ FpmBlockOffset += BlocksPerSection;
+ }
Reader.setOffset(getBlockMapOffset());
if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
OpenPOWER on IntegriCloud