Index: include/llvm/DebugInfo/PDB/Raw/PDBFile.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -47,6 +47,7 @@ ~PDBFile() override; uint32_t getFreeBlockMapBlock() const; + Expected> getUsedBlockList() const; uint32_t getUnknown1() const; uint32_t getBlockSize() const override; Index: lib/DebugInfo/PDB/Raw/PDBFile.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -46,6 +46,22 @@ return ContainerLayout.SB->FreeBlockMapBlock; } +// Returns a vector of used page indices, which is a complement of Free +// Page Map contents. (The reason why we are returning a complement is +// because otherwise the result would be large, as most pages are unused.) +Expected> PDBFile::getUsedBlockList() const { + uint64_t Offset = ContainerLayout.SB->FreeBlockMapBlock * getBlockSize(); + ArrayRef Result; + if (auto EC = Buffer->readBytes(Offset, getBlockSize(), Result)) + return std::move(EC); + + std::vector Vec; + for (uint32_t I = 0, E = getBlockSize() * 8; I != E; ++I) + if ((Result[I / 8] & (1 << (I % 8))) == 0) + Vec.push_back(I); + return Vec; +} + uint32_t PDBFile::getBlockCount() const { return ContainerLayout.SB->NumBlocks; } Index: test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- test/DebugInfo/PDB/pdbdump-headers.test +++ test/DebugInfo/PDB/pdbdump-headers.test @@ -2,7 +2,7 @@ ; RUN: -sym-record-bytes -publics -module-files -stream-name=/names \ ; RUN: -stream-summary -stream-blocks -ipi-records -ipi-record-bytes \ ; RUN: -section-contribs -section-map -section-headers -line-info \ -; RUN: -tpi-hash -fpo %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s +; RUN: -tpi-hash -fpo -fpm %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s ; RUN: llvm-pdbdump raw -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s ; RUN: llvm-pdbdump raw -headers -stream-name=/names -modules -module-files \ ; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s @@ -38,6 +38,7 @@ ; EMPTY-NEXT: Stream 15: [TPI Hash] (308 bytes) ; EMPTY-NEXT: Stream 16: [IPI Hash] (68 bytes) ; EMPTY-NEXT: ] +; EMPTY-NEXT: Used Page Map: [0, 1, 2, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] ; EMPTY-NEXT: StreamBlocks [ ; EMPTY-NEXT: Stream 0: [8] ; EMPTY-NEXT: Stream 1: [19] @@ -973,6 +974,7 @@ ; ALL: Stream 15: [TPI Hash] (308 bytes) ; ALL: Stream 16: [IPI Hash] (68 bytes) ; ALL: ] +; ALL: Used Page Map: [0, 1, 2, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] ; ALL: StreamBlocks [ ; ALL: Stream 0: [8] ; ALL: Stream 1: [19] Index: tools/llvm-pdbdump/LLVMOutputStyle.h =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.h +++ tools/llvm-pdbdump/LLVMOutputStyle.h @@ -26,6 +26,7 @@ private: Error dumpFileHeaders(); Error dumpStreamSummary(); + Error dumpFreePageMap(); Error dumpStreamBlocks(); Error dumpStreamData(); Error dumpInfoStream(); Index: tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -50,6 +50,9 @@ if (auto EC = dumpStreamSummary()) return EC; + if (auto EC = dumpFreePageMap()) + return EC; + if (auto EC = dumpStreamBlocks()) return EC; @@ -234,6 +237,16 @@ return Error::success(); } +Error LLVMOutputStyle::dumpFreePageMap() { + if (!opts::raw::DumpFreePageMap) + return Error::success(); + auto List = File.getUsedBlockList(); + if (!List) + return List.takeError(); + P.printList("Used Page Map", *List); + return Error::success(); +} + Error LLVMOutputStyle::dumpStreamBlocks() { if (!opts::raw::DumpStreamBlocks) return Error::success(); Index: tools/llvm-pdbdump/llvm-pdbdump.h =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.h +++ tools/llvm-pdbdump/llvm-pdbdump.h @@ -37,6 +37,7 @@ extern llvm::cl::opt DumpHeaders; extern llvm::cl::opt DumpStreamBlocks; extern llvm::cl::opt DumpStreamSummary; +extern llvm::cl::opt DumpFreePageMap; extern llvm::cl::opt DumpTpiHash; extern llvm::cl::opt DumpTpiRecordBytes; extern llvm::cl::opt DumpTpiRecords; Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -167,6 +167,8 @@ cl::opt DumpStreamSummary("stream-summary", cl::desc("dump summary of the PDB streams"), cl::cat(MsfOptions), cl::sub(RawSubcommand)); +cl::opt DumpFreePageMap("fpm", cl::desc("dump free page bitmap"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); // TYPE OPTIONS cl::opt @@ -542,6 +544,7 @@ opts::raw::DumpPublics = true; opts::raw::DumpSectionHeaders = true; opts::raw::DumpStreamSummary = true; + opts::raw::DumpFreePageMap = true; opts::raw::DumpStreamBlocks = true; opts::raw::DumpTpiRecords = true; opts::raw::DumpTpiHash = true;