Index: include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -11,9 +11,9 @@ #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeStream.h" namespace llvm { namespace codeview { @@ -51,32 +51,32 @@ #define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) #include "TypeRecords.def" - void visitTypeRecord(const TypeIterator::TypeRecord &Record) { - ArrayRef LeafData = Record.LeafData; + void visitTypeRecord(const TypeIterator::Record &Record) { + ArrayRef LeafData = Record.Data; ArrayRef RecordData = LeafData; auto *DerivedThis = static_cast(this); - DerivedThis->visitTypeBegin(Record.Leaf, RecordData); - switch (Record.Leaf) { + DerivedThis->visitTypeBegin(Record.Type, RecordData); + switch (Record.Type) { default: - DerivedThis->visitUnknownType(Record.Leaf); + DerivedThis->visitUnknownType(Record.Type); break; case LF_FIELDLIST: - DerivedThis->visitFieldList(Record.Leaf, LeafData); + DerivedThis->visitFieldList(Record.Type, LeafData); break; case LF_METHODLIST: - DerivedThis->visitMethodList(Record.Leaf, LeafData); + DerivedThis->visitMethodList(Record.Type, LeafData); break; #define TYPE_RECORD(ClassName, LeafEnum) \ case LeafEnum: { \ const ClassName *Rec; \ if (!CVTypeVisitor::consumeObject(LeafData, Rec)) \ return; \ - DerivedThis->visit##ClassName(Record.Leaf, Rec, LeafData); \ + DerivedThis->visit##ClassName(Record.Type, Rec, LeafData); \ break; \ } #include "TypeRecords.def" } - DerivedThis->visitTypeEnd(Record.Leaf, RecordData); + DerivedThis->visitTypeEnd(Record.Type, RecordData); } /// Visits the type records in Data. Sets the error flag on parse failures. Index: include/llvm/DebugInfo/CodeView/RecordIterator.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/RecordIterator.h @@ -0,0 +1,116 @@ +//===- RecordIterator.h -----------------------------------------*- 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_CODEVIEW_RECORDITERATOR_H +#define LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/support/Endian.h" + +namespace llvm { +namespace codeview { +// A const input iterator interface to the CodeView record stream. +template class RecordIterator { +private: + struct RecordPrefix { + support::ulittle16_t Len; // Record length, starting from &Leaf + support::ulittle16_t Kind; // Record kind (a value from the `Kind` enum). + }; + +public: + struct Record { + std::size_t Length; + Kind Type; + ArrayRef Data; + }; + + explicit RecordIterator(const ArrayRef &RecordBytes) + : Data(RecordBytes), AtEnd(false) { + next(); // Prime the pump + } + + RecordIterator() : AtEnd(true) {} + + // For iterators to compare equal, they must both point at the same record + // in the same data stream, or they must both be at the end of a stream. + friend bool operator==(const RecordIterator &lhs, + const RecordIterator &rhs) { + return (lhs.Data.begin() == rhs.Data.begin()) || (lhs.AtEnd && rhs.AtEnd); + } + + friend bool operator!=(const RecordIterator &lhs, + const RecordIterator &rhs) { + return !(lhs == rhs); + } + + const Record &operator*() const { + assert(!AtEnd); + return Current; + } + + const Record *operator->() const { + assert(!AtEnd); + return &Current; + } + + RecordIterator &operator++() { + next(); + return *this; + } + + RecordIterator operator++(int) { + RecordIterator Original = *this; + ++*this; + return Original; + } + +private: + void next() { + assert(!AtEnd && "Attempted to advance more than one past the last rec"); + if (Data.empty()) { + // We've advanced past the last record. + AtEnd = true; + return; + } + + // FIXME: Use consumeObject when it deals in ArrayRef. + if (Data.size() < sizeof(RecordPrefix)) + return; + const auto *Rec = reinterpret_cast(Data.data()); + Data = Data.drop_front(sizeof(RecordPrefix)); + + Current.Length = Rec->Len; + Current.Type = static_cast(uint16_t(Rec->Kind)); + Current.Data = Data.slice(0, Current.Length - 2); + + // The next record starts immediately after this one. + Data = Data.drop_front(Current.Data.size()); + + // FIXME: The stream contains LF_PAD bytes that we need to ignore, but those + // are typically included in LeafData. We may need to call skipPadding() if + // we ever find a record that doesn't count those bytes. + + return; + } + + ArrayRef Data; + Record Current; + bool AtEnd; +}; + +template +inline iterator_range> +makeRecordRange(ArrayRef Data) { + return make_range(RecordIterator(Data), RecordIterator()); +} +} +} + +#endif Index: include/llvm/DebugInfo/CodeView/SymbolRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_CODEVIEW_SYMBOLRECORD_H #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/Support/Endian.h" @@ -325,6 +326,12 @@ // Name: The null-terminated name follows. }; +typedef RecordIterator SymbolIterator; + +inline iterator_range makeSymbolRange(ArrayRef Data) { + return make_range(SymbolIterator(Data), SymbolIterator()); +} + } // namespace codeview } // namespace llvm Index: include/llvm/DebugInfo/CodeView/TypeDumper.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeDumper.h +++ include/llvm/DebugInfo/CodeView/TypeDumper.h @@ -34,7 +34,7 @@ /// 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::TypeRecord &Record); + bool dump(const TypeIterator::Record &Record); /// Dumps the type records in Data. Returns false if there was a type stream /// parse error, and true otherwise. Index: include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecord.h +++ include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -275,10 +275,6 @@ // A CodeView type stream is a sequence of TypeRecords. Records larger than // 65536 must chain on to a second record. Each TypeRecord is followed by one of // the leaf types described below. -struct TypeRecordPrefix { - ulittle16_t Len; // Type record length, starting from &Leaf. - ulittle16_t Leaf; // Type record kind (TypeLeafKind) -}; // LF_TYPESERVER2 struct TypeServer2 { Index: include/llvm/DebugInfo/CodeView/TypeStream.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeStream.h +++ include/llvm/DebugInfo/CodeView/TypeStream.h @@ -10,13 +10,11 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESTREAM_H #define LLVM_DEBUGINFO_CODEVIEW_TYPESTREAM_H -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/RecordIterator.h" #include "llvm/Object/Error.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorOr.h" #include @@ -62,86 +60,7 @@ /// Decode a numeric leaf value that is known to be a uint32_t. bool decodeUIntLeaf(ArrayRef &Data, uint64_t &Num); -// A const input iterator interface to the CodeView type stream. -class TypeIterator { -public: - struct TypeRecord { - std::size_t Length; - TypeLeafKind Leaf; - ArrayRef LeafData; - }; - - explicit TypeIterator(const ArrayRef &SectionData) - : Data(SectionData), AtEnd(false) { - next(); // Prime the pump - } - - TypeIterator() : AtEnd(true) {} - - // For iterators to compare equal, they must both point at the same record - // in the same data stream, or they must both be at the end of a stream. - friend bool operator==(const TypeIterator &lhs, const TypeIterator &rhs) { - return (lhs.Data.begin() == rhs.Data.begin()) || (lhs.AtEnd && rhs.AtEnd); - } - - friend bool operator!=(const TypeIterator &lhs, const TypeIterator &rhs) { - return !(lhs == rhs); - } - - const TypeRecord &operator*() const { - assert(!AtEnd); - return Current; - } - - const TypeRecord *operator->() const { - assert(!AtEnd); - return &Current; - } - - TypeIterator operator++() { - next(); - return *this; - } - - TypeIterator operator++(int) { - TypeIterator Original = *this; - ++*this; - return Original; - } - -private: - void next() { - assert(!AtEnd && "Attempted to advance more than one past the last rec"); - if (Data.empty()) { - // We've advanced past the last record. - AtEnd = true; - return; - } - - // FIXME: Use consumeObject when it deals in ArrayRef. - if (Data.size() < sizeof(TypeRecordPrefix)) - return; - const auto *Rec = reinterpret_cast(Data.data()); - Data = Data.drop_front(sizeof(TypeRecordPrefix)); - - Current.Length = Rec->Len; - Current.Leaf = static_cast(uint16_t(Rec->Leaf)); - Current.LeafData = Data.slice(0, Current.Length - 2); - - // The next record starts immediately after this one. - Data = Data.drop_front(Current.LeafData.size()); - - // FIXME: The stream contains LF_PAD bytes that we need to ignore, but those - // are typically included in LeafData. We may need to call skipPadding() if - // we ever find a record that doesn't count those bytes. - - return; - } - - ArrayRef Data; - TypeRecord Current; - bool AtEnd; -}; +typedef RecordIterator TypeIterator; inline iterator_range makeTypeRange(ArrayRef Data) { return make_range(TypeIterator(Data), TypeIterator()); Index: lib/DebugInfo/CodeView/TypeDumper.cpp =================================================================== --- lib/DebugInfo/CodeView/TypeDumper.cpp +++ lib/DebugInfo/CodeView/TypeDumper.cpp @@ -755,7 +755,7 @@ W.printHex(FieldName, TI.getIndex()); } -bool CVTypeDumper::dump(const TypeIterator::TypeRecord &Record) { +bool CVTypeDumper::dump(const TypeIterator::Record &Record) { CVTypeDumperImpl Dumper(*this, W, PrintRecordBytes); Dumper.visitTypeRecord(Record); return !Dumper.hadError(); Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -363,7 +363,7 @@ TD.dump(Type); if (opts::DumpTpiRecordBytes) - P.printBinaryBlock("Bytes", Type.LeafData); + P.printBinaryBlock("Bytes", Type.Data); } } return Error::success();