From e8799b644bf5df6c1bbb38f221c5d4d5f1b57a85 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Fri, 27 May 2016 18:47:20 +0000 Subject: [PATCH] Resubmit "[pdb] Allow zero-copy read support for symbol streams."" Due to differences in template instantiation rules, it is not portable to static_assert(false) inside of an invalid specialization of a template. Instead I just =delete the method so that it can't be used, and leave a comment that it must be explicitly specialized. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@271027 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h | 2 +- include/llvm/DebugInfo/CodeView/CVTypeVisitor.h | 2 +- include/llvm/DebugInfo/CodeView/RecordIterator.h | 38 +++++++++--- include/llvm/DebugInfo/CodeView/StreamArray.h | 71 +++++++++++++---------- include/llvm/DebugInfo/CodeView/StreamReader.h | 9 +++ include/llvm/DebugInfo/CodeView/SymbolDumper.h | 2 +- include/llvm/DebugInfo/CodeView/SymbolRecord.h | 4 ++ include/llvm/DebugInfo/CodeView/TypeDumper.h | 2 +- include/llvm/DebugInfo/PDB/Raw/DbiStream.h | 1 - include/llvm/DebugInfo/PDB/Raw/ModInfo.h | 15 ++++- include/llvm/DebugInfo/PDB/Raw/ModStream.h | 6 +- lib/DebugInfo/CodeView/SymbolDumper.cpp | 2 +- lib/DebugInfo/CodeView/TypeDumper.cpp | 2 +- lib/DebugInfo/PDB/Raw/DbiStream.cpp | 10 ++-- lib/DebugInfo/PDB/Raw/ModInfo.cpp | 2 + lib/DebugInfo/PDB/Raw/ModStream.cpp | 13 ++++- 16 files changed, 120 insertions(+), 61 deletions(-) diff --git a/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h index fe21ff9956b..febd9a02615 100644 --- a/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h +++ b/include/llvm/DebugInfo/CodeView/CVSymbolVisitor.h @@ -46,7 +46,7 @@ public: #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "CVSymbolTypes.def" - void visitSymbolRecord(const SymbolIterator::Record &Record) { + void visitSymbolRecord(const CVRecord &Record) { ArrayRef Data = Record.Data; auto *DerivedThis = static_cast(this); DerivedThis->visitSymbolBegin(Record.Type, Data); diff --git a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h index 5058050de56..f9184895d8d 100644 --- a/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ b/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -51,7 +51,7 @@ public: #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) #include "TypeRecords.def" - void visitTypeRecord(const TypeIterator::Record &Record) { + void visitTypeRecord(const CVRecord &Record) { ArrayRef LeafData = Record.Data; ArrayRef RecordData = LeafData; auto *DerivedThis = static_cast(this); diff --git a/include/llvm/DebugInfo/CodeView/RecordIterator.h b/include/llvm/DebugInfo/CodeView/RecordIterator.h index 463e63645d3..a8073eae9c7 100644 --- a/include/llvm/DebugInfo/CodeView/RecordIterator.h +++ b/include/llvm/DebugInfo/CodeView/RecordIterator.h @@ -13,19 +13,41 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/Support/Endian.h" namespace llvm { namespace codeview { +template struct CVRecord { + uint32_t Length; + Kind Type; + ArrayRef Data; +}; + +template struct VarStreamArrayExtractor> { + uint32_t operator()(const StreamInterface &Stream, + CVRecord &Item) const { + const RecordPrefix *Prefix = nullptr; + StreamReader Reader(Stream); + if (auto EC = Reader.readObject(Prefix)) { + consumeError(std::move(EC)); + return 0; + } + Item.Length = Prefix->RecordLen; + Item.Type = static_cast(uint16_t(Prefix->RecordKind)); + if (auto EC = Reader.readBytes(Item.Length - 2, Item.Data)) { + consumeError(std::move(EC)); + return 0; + } + return Prefix->RecordLen + 2; + } +}; + // A const input iterator interface to the CodeView record stream. template class RecordIterator { public: - struct Record { - std::size_t Length; - Kind Type; - ArrayRef Data; - }; explicit RecordIterator(const ArrayRef &RecordBytes, bool *HadError) : HadError(HadError), Data(RecordBytes), AtEnd(false) { @@ -46,12 +68,12 @@ public: return !(lhs == rhs); } - const Record &operator*() const { + const CVRecord &operator*() const { assert(!AtEnd); return Current; } - const Record *operator->() const { + const CVRecord *operator->() const { assert(!AtEnd); return &Current; } @@ -106,7 +128,7 @@ private: bool *HadError; ArrayRef Data; - Record Current; + CVRecord Current; bool AtEnd; }; diff --git a/include/llvm/DebugInfo/CodeView/StreamArray.h b/include/llvm/DebugInfo/CodeView/StreamArray.h index bc21b20d49d..caf70db1fdf 100644 --- a/include/llvm/DebugInfo/CodeView/StreamArray.h +++ b/include/llvm/DebugInfo/CodeView/StreamArray.h @@ -18,6 +18,17 @@ namespace llvm { namespace codeview { +/// VarStreamArrayExtractor is intended to be specialized to provide customized +/// extraction logic. It should return the total number of bytes of the next +/// record (so that the array knows how much data to skip to get to the next +/// record, and it should initialize the second parameter with the desired +/// value type. +template struct VarStreamArrayExtractor { + // Method intentionally deleted. You must provide an explicit specialization + // with the following method implemented. + uint32_t operator()(const StreamInterface &Stream, T &t) const = delete; +}; + /// VarStreamArray represents an array of variable length records backed by a /// stream. This could be a contiguous sequence of bytes in memory, it could /// be a file on disk, or it could be a PDB stream where bytes are stored as @@ -27,33 +38,39 @@ namespace codeview { /// re-ordering of stream data to be contiguous before iterating over it. By /// abstracting this out, we need not duplicate this memory, and we can /// iterate over arrays in arbitrarily formatted streams. -class VarStreamArrayIterator; +template class VarStreamArrayIterator; +template > class VarStreamArray { - friend class VarStreamArrayIterator; - typedef std::function LengthFuncType; + friend class VarStreamArrayIterator; public: - template - VarStreamArray(StreamRef Stream, const LengthFunc &Len) - : Stream(Stream), Len(Len) {} + typedef VarStreamArrayIterator Iterator; + + VarStreamArray() {} + + VarStreamArray(StreamRef Stream) : Stream(Stream) {} - VarStreamArrayIterator begin() const; - VarStreamArrayIterator end() const; + Iterator begin() const { return Iterator(*this); } + + Iterator end() const { return Iterator(); } private: StreamRef Stream; - LengthFuncType Len; // Function used to calculate legth of a record }; -class VarStreamArrayIterator { +template class VarStreamArrayIterator { + typedef VarStreamArrayIterator IterType; + typedef VarStreamArray ArrayType; + public: - VarStreamArrayIterator(const VarStreamArray &Array) + VarStreamArrayIterator(const ArrayType &Array) : Array(&Array), IterRef(Array.Stream) { - ThisLen = Array.Len(IterRef); + ThisLen = Extract(IterRef, ThisValue); } VarStreamArrayIterator() : Array(nullptr), IterRef() {} - bool operator==(const VarStreamArrayIterator &R) const { + bool operator==(const IterType &R) const { if (Array && R.Array) { // Both have a valid array, make sure they're same. assert(Array == R.Array); @@ -68,45 +85,37 @@ public: return false; } - bool operator!=(const VarStreamArrayIterator &R) { return !(*this == R); } + bool operator!=(const IterType &R) { return !(*this == R); } - StreamRef operator*() const { - ArrayRef Result; - return IterRef.keep_front(ThisLen); - } + const ValueType &operator*() const { return ThisValue; } - VarStreamArrayIterator &operator++() { - if (!Array || IterRef.getLength() == 0) + IterType &operator++() { + if (!Array || IterRef.getLength() == 0 || ThisLen == 0) return *this; IterRef = IterRef.drop_front(ThisLen); if (IterRef.getLength() == 0) { Array = nullptr; ThisLen = 0; } else { - ThisLen = Array->Len(IterRef); + ThisLen = Extract(IterRef, ThisValue); } return *this; } - VarStreamArrayIterator operator++(int) { - VarStreamArrayIterator Original = *this; + IterType operator++(int) { + IterType Original = *this; ++*this; return Original; } private: - const VarStreamArray *Array; + const ArrayType *Array; uint32_t ThisLen; + ValueType ThisValue; StreamRef IterRef; + Extractor Extract; }; -inline VarStreamArrayIterator VarStreamArray::begin() const { - return VarStreamArrayIterator(*this); -} -inline VarStreamArrayIterator VarStreamArray::end() const { - return VarStreamArrayIterator(); -} - template class FixedStreamArrayIterator; template class FixedStreamArray { diff --git a/include/llvm/DebugInfo/CodeView/StreamReader.h b/include/llvm/DebugInfo/CodeView/StreamReader.h index 89e2ef0a124..71691dc2643 100644 --- a/include/llvm/DebugInfo/CodeView/StreamReader.h +++ b/include/llvm/DebugInfo/CodeView/StreamReader.h @@ -46,6 +46,15 @@ public: } template + Error readArray(VarStreamArray &Array, uint32_t Size) { + StreamRef S; + if (auto EC = readStreamRef(S, Size)) + return EC; + Array = VarStreamArray(S); + return Error::success(); + } + + template Error readArray(FixedStreamArray &Array, uint32_t NumItems) { if (NumItems == 0) { Array = FixedStreamArray(); diff --git a/include/llvm/DebugInfo/CodeView/SymbolDumper.h b/include/llvm/DebugInfo/CodeView/SymbolDumper.h index 62c5ab3931b..97c795225e2 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolDumper.h +++ b/include/llvm/DebugInfo/CodeView/SymbolDumper.h @@ -35,7 +35,7 @@ public: /// and true otherwise. This should be called in order, since the dumper /// maintains state about previous records which are necessary for cross /// type references. - bool dump(const SymbolIterator::Record &Record); + bool dump(const CVRecord &Record); /// Dumps the type records in Data. Returns false if there was a type stream /// parse error, and true otherwise. diff --git a/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/include/llvm/DebugInfo/CodeView/SymbolRecord.h index 57c7628df73..9ab559d8e27 100644 --- a/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ b/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -15,6 +15,8 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -1441,6 +1443,8 @@ public: }; typedef RecordIterator SymbolIterator; +typedef CVRecord CVSymbol; +typedef VarStreamArray CVSymbolArray; inline iterator_range makeSymbolRange(ArrayRef Data, bool *HadError) { diff --git a/include/llvm/DebugInfo/CodeView/TypeDumper.h b/include/llvm/DebugInfo/CodeView/TypeDumper.h index 3085666fe0f..c74f5cffb91 100644 --- a/include/llvm/DebugInfo/CodeView/TypeDumper.h +++ b/include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -34,7 +34,7 @@ public: /// and true otherwise. This should be called in order, since the dumper /// maintains state about previous records which are necessary for cross /// type references. - bool dump(const TypeIterator::Record &Record); + bool dump(const CVRecord &Record); /// Dumps the type records in Data. Returns false if there was a type stream /// parse error, and true otherwise. diff --git a/include/llvm/DebugInfo/PDB/Raw/DbiStream.h b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h index 17f31f5695f..8a50e138cd2 100644 --- a/include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ b/include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -10,7 +10,6 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H #define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H -#include "llvm/DebugInfo/CodeView/ByteStream.h" #include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" diff --git a/include/llvm/DebugInfo/PDB/Raw/ModInfo.h b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h index 3b79d48a8a1..c9050abe05f 100644 --- a/include/llvm/DebugInfo/PDB/Raw/ModInfo.h +++ b/include/llvm/DebugInfo/PDB/Raw/ModInfo.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamRef.h" #include #include @@ -23,6 +24,7 @@ private: struct FileLayout; public: + ModInfo(); ModInfo(codeview::StreamRef Stream); ModInfo(const ModInfo &Info); ~ModInfo(); @@ -50,6 +52,7 @@ private: struct ModuleInfoEx { ModuleInfoEx(codeview::StreamRef Stream) : Info(Stream) {} + ModuleInfoEx(const ModInfo &Info) : Info(Info) {} ModuleInfoEx(const ModuleInfoEx &Ex) : Info(Ex.Info), SourceFiles(Ex.SourceFiles) {} @@ -57,11 +60,17 @@ struct ModuleInfoEx { std::vector SourceFiles; }; -inline uint32_t ModInfoRecordLength(const codeview::StreamInterface &Stream) { - return ModInfo(Stream).getRecordLength(); +} // end namespace pdb + +namespace codeview { +template <> struct VarStreamArrayExtractor { + uint32_t operator()(const StreamInterface &Stream, pdb::ModInfo &Info) const { + Info = pdb::ModInfo(Stream); + return Info.getRecordLength(); + } +}; } -} // end namespace pdb } // end namespace llvm #endif // LLVM_DEBUGINFO_PDB_RAW_MODINFO_H diff --git a/include/llvm/DebugInfo/PDB/Raw/ModStream.h b/include/llvm/DebugInfo/PDB/Raw/ModStream.h index e5bd2eba4ba..72869134b48 100644 --- a/include/llvm/DebugInfo/PDB/Raw/ModStream.h +++ b/include/llvm/DebugInfo/PDB/Raw/ModStream.h @@ -11,7 +11,7 @@ #define LLVM_DEBUGINFO_PDB_RAW_MODSTREAM_H #include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" @@ -29,14 +29,14 @@ public: Error reload(); - iterator_range symbols() const; + iterator_range symbols() const; private: const ModInfo &Mod; MappedBlockStream Stream; - codeview::ByteStream SymbolsSubstream; + codeview::CVSymbolArray SymbolsSubstream; codeview::StreamRef LinesSubstream; codeview::StreamRef C13LinesSubstream; codeview::StreamRef GlobalRefsSubstream; diff --git a/lib/DebugInfo/CodeView/SymbolDumper.cpp b/lib/DebugInfo/CodeView/SymbolDumper.cpp index 03b711282b4..7d405ec2453 100644 --- a/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -866,7 +866,7 @@ void CVSymbolDumperImpl::visitUnknownSymbol(SymbolKind Kind, W.printNumber("Length", uint32_t(Data.size())); } -bool CVSymbolDumper::dump(const SymbolIterator::Record &Record) { +bool CVSymbolDumper::dump(const CVRecord &Record) { CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); Dumper.visitSymbolRecord(Record); return !Dumper.hadError(); diff --git a/lib/DebugInfo/CodeView/TypeDumper.cpp b/lib/DebugInfo/CodeView/TypeDumper.cpp index 74cb2d9e9c4..1db1e54f430 100644 --- a/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -676,7 +676,7 @@ void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) { W->printHex(FieldName, TI.getIndex()); } -bool CVTypeDumper::dump(const TypeIterator::Record &Record) { +bool CVTypeDumper::dump(const CVRecord &Record) { assert(W && "printer should not be null"); CVTypeDumperImpl Dumper(*this, *W, PrintRecordBytes); Dumper.visitTypeRecord(Record); diff --git a/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/lib/DebugInfo/PDB/Raw/DbiStream.cpp index 35937574645..1827ab078df 100644 --- a/lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ b/lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -136,14 +136,12 @@ Error DbiStream::reload() { return make_error(raw_error_code::corrupt_file, "DBI type server substream not aligned."); - if (auto EC = - Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize)) - return EC; - // Since each ModInfo in the stream is a variable length, we have to iterate // them to know how many there actually are. - codeview::VarStreamArray ModInfoArray(ModInfoSubstream, ModInfoRecordLength); - for (auto Info : ModInfoArray) { + codeview::VarStreamArray ModInfoArray; + if (auto EC = Reader.readArray(ModInfoArray, Header->ModiSubstreamSize)) + return EC; + for (auto &Info : ModInfoArray) { ModuleInfos.emplace_back(Info); } diff --git a/lib/DebugInfo/PDB/Raw/ModInfo.cpp b/lib/DebugInfo/PDB/Raw/ModInfo.cpp index 9ccb7edd696..67dc81da63a 100644 --- a/lib/DebugInfo/PDB/Raw/ModInfo.cpp +++ b/lib/DebugInfo/PDB/Raw/ModInfo.cpp @@ -67,6 +67,8 @@ struct ModInfo::FileLayout { // Null terminated Obj File Name }; +ModInfo::ModInfo() : Layout(nullptr) {} + ModInfo::ModInfo(codeview::StreamRef Stream) : Layout(nullptr) { codeview::StreamReader Reader(Stream); if (auto EC = Reader.readObject(Layout)) { diff --git a/lib/DebugInfo/PDB/Raw/ModStream.cpp b/lib/DebugInfo/PDB/Raw/ModStream.cpp index 38d3f2f23e3..404208a6487 100644 --- a/lib/DebugInfo/PDB/Raw/ModStream.cpp +++ b/lib/DebugInfo/PDB/Raw/ModStream.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Raw/ModStream.h" +#include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" @@ -32,8 +33,14 @@ Error ModStream::reload() { return llvm::make_error(raw_error_code::corrupt_file, "Module has both C11 and C13 line info"); - if (auto EC = SymbolsSubstream.load(Reader, SymbolSize)) + codeview::StreamRef S; + + uint32_t SymbolSubstreamSig = 0; + if (auto EC = Reader.readInteger(SymbolSubstreamSig)) + return EC; + if (auto EC = Reader.readArray(SymbolsSubstream, SymbolSize - 4)) return EC; + if (auto EC = Reader.readStreamRef(LinesSubstream, C11Size)) return EC; if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) @@ -51,6 +58,6 @@ Error ModStream::reload() { return Error::success(); } -iterator_range ModStream::symbols() const { - return codeview::makeSymbolRange(SymbolsSubstream.data().slice(4), nullptr); +iterator_range ModStream::symbols() const { + return llvm::make_range(SymbolsSubstream.begin(), SymbolsSubstream.end()); } -- 2.11.0