diff options
23 files changed, 247 insertions, 143 deletions
diff --git a/llvm/include/llvm/DebugInfo/CodeView/StreamArray.h b/llvm/include/llvm/DebugInfo/CodeView/StreamArray.h index 7dd731df947..0241bb82be2 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/StreamArray.h +++ b/llvm/include/llvm/DebugInfo/CodeView/StreamArray.h @@ -224,6 +224,8 @@ public: return FixedStreamArrayIterator<T>(*this, size()); } + StreamRef getUnderlyingStream() const { return Stream; } + private: StreamRef Stream; }; diff --git a/llvm/include/llvm/DebugInfo/CodeView/StreamReader.h b/llvm/include/llvm/DebugInfo/CodeView/StreamReader.h index a0e6a076b09..0cd779419c5 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/StreamReader.h +++ b/llvm/include/llvm/DebugInfo/CodeView/StreamReader.h @@ -52,6 +52,20 @@ public: return Error::success(); } + template <typename T> + Error readArray(ArrayRef<T> &Array, uint32_t NumElements) { + ArrayRef<uint8_t> Bytes; + if (NumElements == 0) { + Array = ArrayRef<T>(); + return Error::success(); + } + + if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) + return EC; + Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements); + return Error::success(); + } + template <typename T, typename U> Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) { StreamRef S; diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h b/llvm/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h index d76ba9f10ee..a772ef1a7ae 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/IPDBFile.h +++ b/llvm/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 <stdint.h> @@ -28,7 +29,8 @@ public: virtual uint32_t getNumStreams() const = 0; virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0; - virtual ArrayRef<uint32_t> getStreamBlockList(uint32_t StreamIndex) const = 0; + virtual ArrayRef<support::ulittle32_t> + getStreamBlockList(uint32_t StreamIndex) const = 0; virtual StringRef getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const = 0; diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h b/llvm/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h new file mode 100644 index 00000000000..ab3c9f77075 --- /dev/null +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/IPDBStreamData.h @@ -0,0 +1,38 @@ +//===- 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<support::ulittle32_t> getStreamBlocks() = 0; +}; +} +} + +#endif diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h b/llvm/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h new file mode 100644 index 00000000000..30563bc5b89 --- /dev/null +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/IndexedStreamData.h @@ -0,0 +1,34 @@ +//===- 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; + +class IndexedStreamData : public IPDBStreamData { +public: + IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File); + virtual ~IndexedStreamData() {} + + uint32_t getLength() override; + ArrayRef<support::ulittle32_t> getStreamBlocks() override; + +private: + uint32_t StreamIdx; + const IPDBFile &File; +}; +} +} + +#endif diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h b/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h index 39ac2796595..01b0b16e7f8 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/InfoStream.h @@ -24,7 +24,7 @@ namespace pdb { class PDBFile; class InfoStream { public: - InfoStream(PDBFile &File); + InfoStream(const PDBFile &File); Error reload(); @@ -36,10 +36,7 @@ public: uint32_t getNamedStreamIndex(llvm::StringRef Name) const; iterator_range<StringMapConstIterator<uint32_t>> named_streams() const; - PDBFile &getFile() { return Pdb; } - private: - PDBFile &Pdb; MappedBlockStream Stream; // PDB file format version. We only support VC70. See the enumeration diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h b/llvm/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h index e8eb7cf7e27..ea5d0a147ad 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h +++ b/llvm/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 <cstdint> #include <vector> @@ -22,15 +23,16 @@ namespace llvm { namespace pdb { class IPDBFile; +class IPDBStreamData; class MappedBlockStream : public codeview::StreamInterface { public: - MappedBlockStream(uint32_t StreamIdx, const IPDBFile &File); + MappedBlockStream(std::unique_ptr<IPDBStreamData> Data, const IPDBFile &File); Error readBytes(uint32_t Offset, uint32_t Size, ArrayRef<uint8_t> &Buffer) const override; - uint32_t getLength() const override { return StreamLength; } + uint32_t getLength() const override; uint32_t getNumBytesCopied() const; @@ -39,11 +41,11 @@ private: bool tryReadContiguously(uint32_t Offset, uint32_t Size, ArrayRef<uint8_t> &Buffer) const; - uint32_t StreamLength; - std::vector<uint32_t> BlockList; + const IPDBFile &Pdb; + std::unique_ptr<IPDBStreamData> Data; + mutable llvm::BumpPtrAllocator Pool; mutable DenseMap<uint32_t, uint8_t *> CacheMap; - const IPDBFile &Pdb; }; } // end namespace pdb diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h b/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h index b76537f025f..570e513e371 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -26,7 +26,7 @@ class ModInfo; class ModStream { public: - ModStream(PDBFile &File, const ModInfo &Module); + ModStream(const PDBFile &File, const ModInfo &Module); ~ModStream(); Error reload(); diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h b/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h index 1b8dbb898be..d3f269430a7 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ b/llvm/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 @@ public: uint32_t getNumStreams() const override; uint32_t getStreamByteSize(uint32_t StreamIndex) const override; - ArrayRef<uint32_t> getStreamBlockList(uint32_t StreamIndex) const override; + ArrayRef<support::ulittle32_t> + getStreamBlockList(uint32_t StreamIndex) const override; StringRef getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const override; - ArrayRef<support::ulittle32_t> getDirectoryBlockArray(); + ArrayRef<support::ulittle32_t> getDirectoryBlockArray() const; Error parseFileHeaders(); Error parseStreamData(); @@ -81,6 +83,7 @@ private: std::unique_ptr<TpiStream> Ipi; std::unique_ptr<PublicsStream> Publics; std::unique_ptr<SymbolStream> Symbols; + std::unique_ptr<MappedBlockStream> DirectoryStream; std::unique_ptr<MappedBlockStream> StringTableStream; std::unique_ptr<NameHashTable> StringTable; }; diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h b/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h index 1f8598d4410..dc43e221786 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/SymbolStream.h @@ -22,7 +22,7 @@ class PDBFile; class SymbolStream { public: - SymbolStream(PDBFile &File, uint32_t StreamNum); + SymbolStream(const PDBFile &File, uint32_t StreamNum); ~SymbolStream(); Error reload(); diff --git a/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h b/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h index 52fd31a90b0..a3eb8e6af55 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h +++ b/llvm/include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -31,7 +31,7 @@ class TpiStream { struct HeaderInfo; public: - TpiStream(PDBFile &File, uint32_t StreamIdx); + TpiStream(const PDBFile &File, uint32_t StreamIdx); ~TpiStream(); Error reload(); @@ -50,7 +50,7 @@ public: iterator_range<codeview::CVTypeArray::Iterator> types(bool *HadError) const; private: - PDBFile &Pdb; + const PDBFile &Pdb; MappedBlockStream Stream; HashFunctionType HashFunction; diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt index 46074f769cd..336729d3543 100644 --- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt +++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt @@ -30,6 +30,7 @@ endif() add_pdb_impl_folder(Raw Raw/DbiStream.cpp Raw/EnumTables.cpp + Raw/IndexedStreamData.cpp Raw/InfoStream.cpp Raw/MappedBlockStream.cpp Raw/ModInfo.cpp diff --git a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp index b1c571bf78c..80441ccd825 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ b/llvm/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 @@ Error loadSectionContribs(FixedStreamArray<ContribType> &Output, } DbiStream::DbiStream(PDBFile &File) - : Pdb(File), Stream(StreamDBI, File), Header(nullptr) { + : Pdb(File), + Stream(llvm::make_unique<IndexedStreamData>(StreamDBI, File), File), + Header(nullptr) { static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!"); } @@ -290,7 +293,8 @@ Error DbiStream::initializeSectionContributionData() { // 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<IndexedStreamData>(StreamNum, Pdb), Pdb)); size_t StreamLen = SectionHeaderStream->getLength(); if (StreamLen % sizeof(object::coff_section)) @@ -308,7 +312,8 @@ Error DbiStream::initializeSectionHeadersData() { // 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<IndexedStreamData>(StreamNum, Pdb), Pdb)); size_t StreamLen = FpoStream->getLength(); if (StreamLen % sizeof(object::FpoData)) diff --git a/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp b/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp new file mode 100644 index 00000000000..9bd16ea76ef --- /dev/null +++ b/llvm/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<support::ulittle32_t> IndexedStreamData::getStreamBlocks() { + return File.getStreamBlockList(StreamIdx); +} diff --git a/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp index 4388ed41664..0f2fd24395c 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ b/llvm/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<IndexedStreamData>(StreamPDB, File), File) {} Error InfoStream::reload() { codeview::StreamReader Reader(Stream); diff --git a/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp index 34d16712271..03462b38863 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp +++ b/llvm/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<IPDBStreamData> Data, + const IPDBFile &Pdb) + : Pdb(Pdb), Data(std::move(Data)) {} Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, ArrayRef<uint8_t> &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<RawError>(raw_error_code::insufficient_buffer); - if (Offset > StreamLength - Size) + if (Offset > Data->getLength() - Size) return make_error<RawError>(raw_error_code::insufficient_buffer); if (tryReadContiguously(Offset, Size, Buffer)) @@ -57,6 +52,8 @@ Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, return Error::success(); } +uint32_t MappedBlockStream::getLength() const { return Data->getLength(); } + bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, ArrayRef<uint8_t> &Buffer) const { // Attempt to fulfill the request with a reference directly into the stream. @@ -72,6 +69,7 @@ bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, 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 @@ Error MappedBlockStream::readBytes(uint32_t Offset, 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<RawError>(raw_error_code::insufficient_buffer); - if (Offset > StreamLength - Buffer.size()) + if (Offset > Data->getLength() - Buffer.size()) return make_error<RawError>(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]; diff --git a/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp index 14c55906e06..57c455e0a00 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp +++ b/llvm/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<IndexedStreamData>( + Module.getModuleStreamIndex(), File), + File) {} ModStream::~ModStream() {} diff --git a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp index 73d8eef570f..81762e7f879 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ b/llvm/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 @@ struct SuperBlock { // 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<llvm::support::ulittle32_t> getStreamBlocks() { + return File.getDirectoryBlockArray(); + } + +private: + const PDBFile &File; +}; + +typedef codeview::FixedStreamArray<support::ulittle32_t> ulittle_array; } struct llvm::pdb::PDBFileContext { std::unique_ptr<MemoryBuffer> Buffer; const SuperBlock *SB; - std::vector<uint32_t> StreamSizes; - DenseMap<uint32_t, std::vector<uint32_t>> StreamMap; + ArrayRef<support::ulittle32_t> StreamSizes; + std::vector<ulittle_array> StreamMap; }; static Error checkOffset(MemoryBufferRef M, uintptr_t Addr, @@ -109,10 +128,14 @@ uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { return Context->StreamSizes[StreamIndex]; } -llvm::ArrayRef<uint32_t> +ArrayRef<support::ulittle32_t> PDBFile::getStreamBlockList(uint32_t StreamIndex) const { - auto &Data = Context->StreamMap[StreamIndex]; - return llvm::ArrayRef<uint32_t>(Data); + auto Result = Context->StreamMap[StreamIndex]; + codeview::StreamReader Reader(Result.getUnderlyingStream()); + ArrayRef<support::ulittle32_t> Array; + if (auto EC = Reader.readArray(Array, Result.size())) + return ArrayRef<support::ulittle32_t>(); + return Array; } StringRef PDBFile::getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const { @@ -184,113 +207,44 @@ Error PDBFile::parseFileHeaders() { 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<const support::ulittle32_t *>( - 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<uint32_t> *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<RawError>(raw_error_code::corrupt_file, - "Orphaned block found?"); - - uint64_t BlockOffset = blockToOffset(Data, getBlockSize()); - if (BlockOffset + getBlockSize() < BlockOffset) - return make_error<RawError>(raw_error_code::corrupt_file, - "Bogus stream block number"); - if (BlockOffset + getBlockSize() > M.getBufferSize()) - return make_error<RawError>(raw_error_code::corrupt_file, - "Stream block number is out of bounds"); - - StreamBlocks->push_back(Data); - } - } - - if (Context->StreamSizes.size() != NumStreams) - return make_error<RawError>( - 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<DirectoryStreamData>(*this); + DirectoryStream = llvm::make_unique<MappedBlockStream>(std::move(SD), *this); + codeview::StreamReader Reader(*DirectoryStream); + if (auto EC = Reader.readInteger(NumStreams)) + return EC; - for (uint32_t I = 0; I != NumStreams; ++I) { + 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<RawError>(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<support::ulittle32_t> PDBFile::getDirectoryBlockArray() { +llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { return makeArrayRef( reinterpret_cast<const support::ulittle32_t *>( Context->Buffer->getBufferStart() + getBlockMapOffset()), @@ -371,7 +325,8 @@ Expected<NameHashTable &> PDBFile::getStringTable() { if (NameStreamIndex == 0) return make_error<RawError>(raw_error_code::no_stream); - auto S = llvm::make_unique<MappedBlockStream>(NameStreamIndex, *this); + auto SD = llvm::make_unique<IndexedStreamData>(NameStreamIndex, *this); + auto S = llvm::make_unique<MappedBlockStream>(std::move(SD), *this); codeview::StreamReader Reader(*S); auto N = llvm::make_unique<NameHashTable>(); if (auto EC = N->load(Reader)) diff --git a/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp index d3a7ffd7f93..e3e100806ee 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp +++ b/llvm/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 @@ struct PublicsStream::GSIHashHeader { }; PublicsStream::PublicsStream(PDBFile &File, uint32_t StreamNum) - : Pdb(File), StreamNum(StreamNum), Stream(StreamNum, File) {} + : Pdb(File), StreamNum(StreamNum), + Stream(llvm::make_unique<IndexedStreamData>(StreamNum, File), File) {} PublicsStream::~PublicsStream() {} diff --git a/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp index 8b358b04f68..b6267a7f3f4 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp +++ b/llvm/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; 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<IndexedStreamData>(StreamNum, File), + File) {} SymbolStream::~SymbolStream() {} diff --git a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp index 11e10a58e5d..9d8a45ebc88 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ b/llvm/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 @@ struct TpiStream::HeaderInfo { 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<IndexedStreamData>(StreamIdx, File), File), + HashFunction(nullptr) {} TpiStream::~TpiStream() {} @@ -101,7 +104,8 @@ Error TpiStream::reload() { 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<IndexedStreamData>(Header->HashStreamIndex, Pdb), Pdb)); codeview::StreamReader HSR(*HashStream); uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); diff --git a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp.rej b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp.rej new file mode 100644 index 00000000000..3547269eff4 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp.rej @@ -0,0 +1,11 @@ +diff a/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/lib/DebugInfo/PDB/Raw/TpiStream.cpp (rejected hunks) +@@ -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<IndexedStreamData>(Header->HashStreamIndex, Pdb), Pdb)); + codeview::StreamReader HSR(*HashStream); + uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); + HSR.setOffset(Header->HashValueBuffer.Off); diff --git a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp b/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp index 034879bf0f4..f819a2cfc92 100644 --- a/llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ b/llvm/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 @@ Error LLVMOutputStyle::dumpStreamData() { DumpStreamNum >= StreamCount) return Error::success(); - MappedBlockStream S(DumpStreamNum, File); + MappedBlockStream S(llvm::make_unique<IndexedStreamData>(DumpStreamNum, File), + File); codeview::StreamReader R(S); while (R.bytesRemaining() > 0) { ArrayRef<uint8_t> Data; @@ -244,7 +246,8 @@ Error LLVMOutputStyle::dumpNamedStream() { DictScope D(P, Name); P.printNumber("Index", NameStreamIndex); - MappedBlockStream NameStream(NameStreamIndex, File); + MappedBlockStream NameStream( + llvm::make_unique<IndexedStreamData>(NameStreamIndex, File), File); codeview::StreamReader Reader(NameStream); NameHashTable NameTable; |