Index: include/llvm/DebugInfo/CodeView/StreamArray.h =================================================================== --- include/llvm/DebugInfo/CodeView/StreamArray.h +++ include/llvm/DebugInfo/CodeView/StreamArray.h @@ -224,6 +224,8 @@ return FixedStreamArrayIterator(*this, size()); } + StreamRef getUnderlyingStream() const { return Stream; } + private: StreamRef Stream; }; Index: include/llvm/DebugInfo/CodeView/StreamReader.h =================================================================== --- include/llvm/DebugInfo/CodeView/StreamReader.h +++ include/llvm/DebugInfo/CodeView/StreamReader.h @@ -52,6 +52,20 @@ return Error::success(); } + template + Error readArray(ArrayRef &Array, uint32_t NumElements) { + ArrayRef Bytes; + if (NumElements == 0) { + Array = ArrayRef(); + return Error::success(); + } + + if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) + return EC; + Array = ArrayRef(reinterpret_cast(Bytes.data()), NumElements); + return Error::success(); + } + template Error readArray(VarStreamArray &Array, uint32_t Size) { StreamRef S; Index: include/llvm/DebugInfo/PDB/Raw/IPDBFile.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/IPDBFile.h +++ include/llvm/DebugInfo/PDB/Raw/IPDBFile.h @@ -12,6 +12,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/Support/Endian.h" #include @@ -28,7 +29,8 @@ virtual uint32_t getNumStreams() const = 0; virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0; - virtual ArrayRef getStreamBlockList(uint32_t StreamIndex) const = 0; + virtual ArrayRef + getStreamBlockList(uint32_t StreamIndex) const = 0; virtual StringRef getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const = 0; Index: include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h @@ -0,0 +1,39 @@ +//===- IPDBStreamData.h - Base interface for PDB Stream Data -----*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_IPDBSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_IPDBSTREAMDATA_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace pdb { +/// IPDBStream abstracts the notion of PDB stream data. Although we already +/// have another stream abstraction (namely in the form of StreamInterface +/// and MappedBlockStream), they assume that the stream data is referenced +/// the same way. Namely, by looking in the directory to get the list of +/// stream blocks, and by looking in the array of stream lengths to get the +/// length. This breaks down for the directory itself, however, since its +/// length and list of blocks are stored elsewhere. By abstracting the +/// notion of stream data further, we can use a MappedBlockStream to read +/// from the directory itself, or from an indexed stream which references +/// the directory. +class IPDBStreamData { +public: + virtual ~IPDBStreamData() {} + + virtual uint32_t getLength() = 0; + virtual ArrayRef getStreamBlocks() = 0; +}; +} +} + +#endif Index: include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h @@ -0,0 +1,44 @@ +//===- IndexedStreamData.h - Standard PDB Stream Data -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_INDEXEDSTREAMDATA_H +#define LLVM_DEBUGINFO_PDB_RAW_INDEXEDSTREAMDATA_H + +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" + +namespace llvm { +namespace pdb { +class IPDBFile; + +/// IPDBStream abstracts the notion of PDB stream data. Although we already +/// have another stream abstraction (namely in the form of StreamInterface +/// and MappedBlockStream), they assume that the stream data is referenced +/// the same way. Namely, by looking in the directory to get the list of +/// stream blocks, and by looking in the array of stream lengths to get the +/// length. This breaks down for the directory itself, however, since its +/// length and list of blocks are stored elsewhere. By abstracting the +/// notion of stream data further, we can use a MappedBlockStream to read +/// from the directory itself, or from an indexed stream which references +/// the directory. +class IndexedStreamData : public IPDBStreamData { +public: + IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File); + virtual ~IndexedStreamData() {} + + uint32_t getLength() override; + ArrayRef getStreamBlocks() override; + +private: + uint32_t StreamIdx; + const IPDBFile &File; +}; +} +} + +#endif Index: include/llvm/DebugInfo/PDB/Raw/InfoStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/InfoStream.h +++ include/llvm/DebugInfo/PDB/Raw/InfoStream.h @@ -24,7 +24,7 @@ class PDBFile; class InfoStream { public: - InfoStream(PDBFile &File); + InfoStream(const PDBFile &File); Error reload(); @@ -36,10 +36,7 @@ uint32_t getNamedStreamIndex(llvm::StringRef Name) const; iterator_range> named_streams() const; - PDBFile &getFile() { return Pdb; } - private: - PDBFile &Pdb; MappedBlockStream Stream; // PDB file format version. We only support VC70. See the enumeration Index: include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h +++ include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h @@ -14,6 +14,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/CodeView/StreamInterface.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include #include @@ -22,15 +23,16 @@ namespace pdb { class IPDBFile; +class IPDBStreamData; class MappedBlockStream : public codeview::StreamInterface { public: - MappedBlockStream(uint32_t StreamIdx, const IPDBFile &File); + MappedBlockStream(std::unique_ptr Data, const IPDBFile &File); Error readBytes(uint32_t Offset, uint32_t Size, ArrayRef &Buffer) const override; - uint32_t getLength() const override { return StreamLength; } + uint32_t getLength() const override; uint32_t getNumBytesCopied() const; @@ -39,11 +41,11 @@ bool tryReadContiguously(uint32_t Offset, uint32_t Size, ArrayRef &Buffer) const; - uint32_t StreamLength; - std::vector BlockList; + const IPDBFile &Pdb; + std::unique_ptr Data; + mutable llvm::BumpPtrAllocator Pool; mutable DenseMap CacheMap; - const IPDBFile &Pdb; }; } // end namespace pdb Index: include/llvm/DebugInfo/PDB/Raw/ModStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/ModStream.h +++ include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -26,7 +26,7 @@ class ModStream { public: - ModStream(PDBFile &File, const ModInfo &Module); + ModStream(const PDBFile &File, const ModInfo &Module); ~ModStream(); Error reload(); Index: include/llvm/DebugInfo/PDB/Raw/PDBFile.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H #include "llvm/ADT/DenseMap.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -48,11 +49,12 @@ uint32_t getNumStreams() const override; uint32_t getStreamByteSize(uint32_t StreamIndex) const override; - ArrayRef getStreamBlockList(uint32_t StreamIndex) const override; + ArrayRef + getStreamBlockList(uint32_t StreamIndex) const override; StringRef getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const override; - ArrayRef getDirectoryBlockArray(); + ArrayRef getDirectoryBlockArray() const; Error parseFileHeaders(); Error parseStreamData(); @@ -81,6 +83,7 @@ std::unique_ptr Ipi; std::unique_ptr Publics; std::unique_ptr Symbols; + std::unique_ptr DirectoryStream; std::unique_ptr StringTableStream; std::unique_ptr StringTable; }; Index: include/llvm/DebugInfo/PDB/Raw/SymbolStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/SymbolStream.h +++ include/llvm/DebugInfo/PDB/Raw/SymbolStream.h @@ -22,7 +22,7 @@ class SymbolStream { public: - SymbolStream(PDBFile &File, uint32_t StreamNum); + SymbolStream(const PDBFile &File, uint32_t StreamNum); ~SymbolStream(); Error reload(); Index: include/llvm/DebugInfo/PDB/Raw/TpiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/TpiStream.h +++ include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -31,7 +31,7 @@ struct HeaderInfo; public: - TpiStream(PDBFile &File, uint32_t StreamIdx); + TpiStream(const PDBFile &File, uint32_t StreamIdx); ~TpiStream(); Error reload(); @@ -50,7 +50,7 @@ iterator_range types(bool *HadError) const; private: - PDBFile &Pdb; + const PDBFile &Pdb; MappedBlockStream Stream; HashFunctionType HashFunction; Index: lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- lib/DebugInfo/PDB/CMakeLists.txt +++ lib/DebugInfo/PDB/CMakeLists.txt @@ -30,6 +30,7 @@ add_pdb_impl_folder(Raw Raw/DbiStream.cpp Raw/EnumTables.cpp + Raw/IndexedStreamData.cpp Raw/InfoStream.cpp Raw/MappedBlockStream.cpp Raw/ModInfo.cpp Index: lib/DebugInfo/PDB/Raw/DbiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -12,6 +12,7 @@ #include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" @@ -93,7 +94,9 @@ } DbiStream::DbiStream(PDBFile &File) - : Pdb(File), Stream(StreamDBI, File), Header(nullptr) { + : Pdb(File), + Stream(llvm::make_unique(StreamDBI, File), File), + Header(nullptr) { static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!"); } @@ -290,7 +293,8 @@ // Initializes this->SectionHeaders. Error DbiStream::initializeSectionHeadersData() { uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::SectionHdr); - SectionHeaderStream.reset(new MappedBlockStream(StreamNum, Pdb)); + SectionHeaderStream.reset(new MappedBlockStream( + llvm::make_unique(StreamNum, Pdb), Pdb)); size_t StreamLen = SectionHeaderStream->getLength(); if (StreamLen % sizeof(object::coff_section)) @@ -308,7 +312,8 @@ // Initializes this->Fpos. Error DbiStream::initializeFpoRecords() { uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO); - FpoStream.reset(new MappedBlockStream(StreamNum, Pdb)); + FpoStream.reset(new MappedBlockStream( + llvm::make_unique(StreamNum, Pdb), Pdb)); size_t StreamLen = FpoStream->getLength(); if (StreamLen % sizeof(object::FpoData)) Index: lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp @@ -0,0 +1,25 @@ +//===- IndexedStreamData.cpp - Standard PDB Stream Data ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" + +using namespace llvm; +using namespace llvm::pdb; + +IndexedStreamData::IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File) + : StreamIdx(StreamIdx), File(File) {} + +uint32_t IndexedStreamData::getLength() { + return File.getStreamByteSize(StreamIdx); +} + +ArrayRef IndexedStreamData::getStreamBlocks() { + return File.getStreamBlockList(StreamIdx); +} Index: lib/DebugInfo/PDB/Raw/InfoStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ lib/DebugInfo/PDB/Raw/InfoStream.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" @@ -18,7 +19,8 @@ using namespace llvm; using namespace llvm::pdb; -InfoStream::InfoStream(PDBFile &File) : Pdb(File), Stream(StreamPDB, File) {} +InfoStream::InfoStream(const PDBFile &File) + : Stream(llvm::make_unique(StreamPDB, File), File) {} Error InfoStream::reload() { codeview::StreamReader Reader(Stream); Index: lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp +++ lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp @@ -8,28 +8,23 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" using namespace llvm; using namespace llvm::pdb; -MappedBlockStream::MappedBlockStream(uint32_t StreamIdx, const IPDBFile &File) - : Pdb(File) { - if (StreamIdx >= Pdb.getNumStreams()) { - StreamLength = 0; - } else { - StreamLength = Pdb.getStreamByteSize(StreamIdx); - BlockList = Pdb.getStreamBlockList(StreamIdx); - } -} +MappedBlockStream::MappedBlockStream(std::unique_ptr Data, + const IPDBFile &Pdb) + : Pdb(Pdb), Data(std::move(Data)) {} Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, ArrayRef &Buffer) const { // Make sure we aren't trying to read beyond the end of the stream. - if (Size > StreamLength) + if (Size > Data->getLength()) return make_error(raw_error_code::insufficient_buffer); - if (Offset > StreamLength - Size) + if (Offset > Data->getLength() - Size) return make_error(raw_error_code::insufficient_buffer); if (tryReadContiguously(Offset, Size, Buffer)) @@ -57,6 +52,8 @@ return Error::success(); } +uint32_t MappedBlockStream::getLength() const { return Data->getLength(); } + bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, ArrayRef &Buffer) const { // Attempt to fulfill the request with a reference directly into the stream. @@ -72,6 +69,7 @@ llvm::alignTo(Size - BytesFromFirstBlock, Pdb.getBlockSize()) / Pdb.getBlockSize(); + auto BlockList = Data->getStreamBlocks(); uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; uint32_t E = BlockList[BlockNum]; for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { @@ -93,14 +91,15 @@ uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); // Make sure we aren't trying to read beyond the end of the stream. - if (Buffer.size() > StreamLength) + if (Buffer.size() > Data->getLength()) return make_error(raw_error_code::insufficient_buffer); - if (Offset > StreamLength - Buffer.size()) + if (Offset > Data->getLength() - Buffer.size()) return make_error(raw_error_code::insufficient_buffer); uint32_t BytesLeft = Buffer.size(); uint32_t BytesWritten = 0; uint8_t *WriteBuffer = Buffer.data(); + auto BlockList = Data->getStreamBlocks(); while (BytesLeft > 0) { uint32_t StreamBlockAddr = BlockList[BlockNum]; Index: lib/DebugInfo/PDB/Raw/ModStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/ModStream.cpp +++ lib/DebugInfo/PDB/Raw/ModStream.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/Raw/ModStream.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" @@ -18,8 +19,10 @@ using namespace llvm; using namespace llvm::pdb; -ModStream::ModStream(PDBFile &File, const ModInfo &Module) - : Mod(Module), Stream(Module.getModuleStreamIndex(), File) {} +ModStream::ModStream(const PDBFile &File, const ModInfo &Module) + : Mod(Module), Stream(llvm::make_unique( + Module.getModuleStreamIndex(), File), + File) {} ModStream::~ModStream() {} Index: lib/DebugInfo/PDB/Raw/PDBFile.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -8,8 +8,12 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" + #include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" @@ -49,13 +53,28 @@ // This contains the block # of the block map. support::ulittle32_t BlockMapAddr; }; + +class DirectoryStreamData : public IPDBStreamData { +public: + DirectoryStreamData(const PDBFile &File) : File(File) {} + + virtual uint32_t getLength() { return File.getNumDirectoryBytes(); } + virtual llvm::ArrayRef getStreamBlocks() { + return File.getDirectoryBlockArray(); + } + +private: + const PDBFile &File; +}; + +typedef codeview::FixedStreamArray ulittle_array; } struct llvm::pdb::PDBFileContext { std::unique_ptr Buffer; const SuperBlock *SB; - std::vector StreamSizes; - DenseMap> StreamMap; + ArrayRef StreamSizes; + std::vector StreamMap; }; static Error checkOffset(MemoryBufferRef M, uintptr_t Addr, @@ -109,10 +128,14 @@ return Context->StreamSizes[StreamIndex]; } -llvm::ArrayRef +ArrayRef PDBFile::getStreamBlockList(uint32_t StreamIndex) const { - auto &Data = Context->StreamMap[StreamIndex]; - return llvm::ArrayRef(Data); + auto Result = Context->StreamMap[StreamIndex]; + codeview::StreamReader Reader(Result.getUnderlyingStream()); + ArrayRef Array; + if (auto EC = Reader.readArray(Array, Result.size())) + return ArrayRef(); + return Array; } StringRef PDBFile::getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const { @@ -184,113 +207,46 @@ Error PDBFile::parseStreamData() { assert(Context && Context->SB); + if (DirectoryStream) + return Error::success(); - bool SeenNumStreams = false; + // bool SeenNumStreams = false; uint32_t NumStreams = 0; - uint32_t StreamIdx = 0; - uint64_t DirectoryBytesRead = 0; + // uint32_t StreamIdx = 0; + // uint64_t DirectoryBytesRead = 0; MemoryBufferRef M = *Context->Buffer; const SuperBlock *SB = Context->SB; - auto DirectoryBlocks = getDirectoryBlockArray(); - - // The structure of the directory is as follows: - // struct PDBDirectory { - // uint32_t NumStreams; - // uint32_t StreamSizes[NumStreams]; - // uint32_t StreamMap[NumStreams][]; - // }; - // - // Empty streams don't consume entries in the StreamMap. - for (uint32_t DirectoryBlockAddr : DirectoryBlocks) { - uint64_t DirectoryBlockOffset = - blockToOffset(DirectoryBlockAddr, SB->BlockSize); - auto DirectoryBlock = - makeArrayRef(reinterpret_cast( - M.getBufferStart() + DirectoryBlockOffset), - SB->BlockSize / sizeof(support::ulittle32_t)); - if (auto EC = checkOffset(M, DirectoryBlock)) - return EC; - - // We read data out of the directory four bytes at a time. Depending on - // where we are in the directory, the contents may be: the number of streams - // in the directory, a stream's size, or a block in the stream map. - for (uint32_t Data : DirectoryBlock) { - // Don't read beyond the end of the directory. - if (DirectoryBytesRead == SB->NumDirectoryBytes) - break; - - DirectoryBytesRead += sizeof(Data); - - // This data must be the number of streams if we haven't seen it yet. - if (!SeenNumStreams) { - NumStreams = Data; - SeenNumStreams = true; - continue; - } - // This data must be a stream size if we have not seen them all yet. - if (Context->StreamSizes.size() < NumStreams) { - // It seems like some streams have their set to -1 when their contents - // are not present. Treat them like empty streams for now. - if (Data == UINT32_MAX) - Context->StreamSizes.push_back(0); - else - Context->StreamSizes.push_back(Data); - continue; - } - - // This data must be a stream block number if we have seen all of the - // stream sizes. - std::vector *StreamBlocks = nullptr; - // Figure out which stream this block number belongs to. - while (StreamIdx < NumStreams) { - uint64_t NumExpectedStreamBlocks = - bytesToBlocks(Context->StreamSizes[StreamIdx], SB->BlockSize); - StreamBlocks = &Context->StreamMap[StreamIdx]; - if (NumExpectedStreamBlocks > StreamBlocks->size()) - break; - ++StreamIdx; - } - // It seems this block doesn't belong to any stream? The stream is either - // corrupt or something more mysterious is going on. - if (StreamIdx == NumStreams) - return make_error(raw_error_code::corrupt_file, - "Orphaned block found?"); - - uint64_t BlockOffset = blockToOffset(Data, getBlockSize()); - if (BlockOffset + getBlockSize() < BlockOffset) - return make_error(raw_error_code::corrupt_file, - "Bogus stream block number"); - if (BlockOffset + getBlockSize() > M.getBufferSize()) - return make_error(raw_error_code::corrupt_file, - "Stream block number is out of bounds"); - - StreamBlocks->push_back(Data); - } - } - - if (Context->StreamSizes.size() != NumStreams) - return make_error( - raw_error_code::corrupt_file, - "The directory has fewer streams then expected"); + // Normally you can't use a MappedBlockStream without having fully parsed the + // PDB file, because it accesses the directory and various other things, which + // is exactly what we are attempting to parse. By specifying a custom + // subclass of IPDBStreamData which only accesses the fields that have already + // been parsed, we can avoid this and reuse MappedBlockStream. + auto SD = llvm::make_unique(*this); + DirectoryStream = llvm::make_unique(std::move(SD), *this); + codeview::StreamReader Reader(*DirectoryStream); + if (auto EC = Reader.readInteger(NumStreams)) + return EC; - for (uint32_t I = 0; I != NumStreams; ++I) { + auto DirectoryBlocks = getDirectoryBlockArray(); + if (auto EC = Reader.readArray(Context->StreamSizes, NumStreams)) + return EC; + for (uint32_t I = 0; I < NumStreams; ++I) { uint64_t NumExpectedStreamBlocks = - bytesToBlocks(getStreamByteSize(I), getBlockSize()); - size_t NumStreamBlocks = getStreamBlockList(I).size(); - if (NumExpectedStreamBlocks != NumStreamBlocks) - return make_error(raw_error_code::corrupt_file, - "The number of stream blocks is not " - "sufficient for the size of this stream"); + bytesToBlocks(getStreamByteSize(I), SB->BlockSize); + ulittle_array Blocks; + if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) + return EC; + Context->StreamMap.push_back(Blocks); } // We should have read exactly SB->NumDirectoryBytes bytes. - assert(DirectoryBytesRead == SB->NumDirectoryBytes); + assert(Reader.bytesRemaining() == 0); return Error::success(); } -llvm::ArrayRef PDBFile::getDirectoryBlockArray() { +llvm::ArrayRef PDBFile::getDirectoryBlockArray() const { return makeArrayRef( reinterpret_cast( Context->Buffer->getBufferStart() + getBlockMapOffset()), @@ -371,7 +327,8 @@ if (NameStreamIndex == 0) return make_error(raw_error_code::no_stream); - auto S = llvm::make_unique(NameStreamIndex, *this); + auto SD = llvm::make_unique(NameStreamIndex, *this); + auto S = llvm::make_unique(std::move(SD), *this); codeview::StreamReader Reader(*S); auto N = llvm::make_unique(); if (auto EC = N->load(Reader)) Index: lib/DebugInfo/PDB/Raw/PublicsStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PublicsStream.cpp +++ lib/DebugInfo/PDB/Raw/PublicsStream.cpp @@ -27,6 +27,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" @@ -71,7 +72,8 @@ }; PublicsStream::PublicsStream(PDBFile &File, uint32_t StreamNum) - : Pdb(File), StreamNum(StreamNum), Stream(StreamNum, File) {} + : Pdb(File), StreamNum(StreamNum), + Stream(llvm::make_unique(StreamNum, File), File) {} PublicsStream::~PublicsStream() {} Index: lib/DebugInfo/PDB/Raw/SymbolStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/SymbolStream.cpp +++ lib/DebugInfo/PDB/Raw/SymbolStream.cpp @@ -12,6 +12,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" @@ -23,8 +24,9 @@ using namespace llvm::support; using namespace llvm::pdb; -SymbolStream::SymbolStream(PDBFile &File, uint32_t StreamNum) - : MappedStream(StreamNum, File) {} +SymbolStream::SymbolStream(const PDBFile &File, uint32_t StreamNum) + : MappedStream(llvm::make_unique(StreamNum, File), + File) {} SymbolStream::~SymbolStream() {} Index: lib/DebugInfo/PDB/Raw/TpiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" @@ -61,8 +62,10 @@ EmbeddedBuf HashAdjBuffer; }; -TpiStream::TpiStream(PDBFile &File, uint32_t StreamIdx) - : Pdb(File), Stream(StreamIdx, File), HashFunction(nullptr) {} +TpiStream::TpiStream(const PDBFile &File, uint32_t StreamIdx) + : Pdb(File), + Stream(llvm::make_unique(StreamIdx, File), File), + HashFunction(nullptr) {} TpiStream::~TpiStream() {} @@ -101,7 +104,8 @@ return EC; // Hash indices, hash values, etc come from the hash stream. - HashStream.reset(new MappedBlockStream(Header->HashStreamIndex, Pdb)); + HashStream.reset(new MappedBlockStream( + llvm::make_unique(Header->HashStreamIndex, Pdb), Pdb)); codeview::StreamReader HSR(*HashStream); uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); HSR.setOffset(Header->HashValueBuffer.Off); Index: tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/EnumTables.h" #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/ModStream.h" @@ -194,7 +195,8 @@ DumpStreamNum >= StreamCount) return Error::success(); - MappedBlockStream S(DumpStreamNum, File); + MappedBlockStream S(llvm::make_unique(DumpStreamNum, File), + File); codeview::StreamReader R(S); while (R.bytesRemaining() > 0) { ArrayRef Data; @@ -244,7 +246,8 @@ DictScope D(P, Name); P.printNumber("Index", NameStreamIndex); - MappedBlockStream NameStream(NameStreamIndex, File); + MappedBlockStream NameStream( + llvm::make_unique(NameStreamIndex, File), File); codeview::StreamReader Reader(NameStream); NameHashTable NameTable;