From 963a331a7e35043a49b00c7132a3eac742ece1ed Mon Sep 17 00:00:00 2001 From: Adrian McCarthy Date: Mon, 2 May 2016 23:45:03 +0000 Subject: [PATCH] NFC: An iterator for stepping through CodeView type stream in llvm-readobj This is a small refactoring step toward moving CodeView type stream logic from llvm-readobj to a library. It abstracts the logic of stepping through the stream into an iterator class and updates llvm-readobj to use that iterator. This has no functional change; llvm-readobj produces identical output. The next step is to abstract the parsing of the different leaf types and then move that and the iterator into a library. Since this is my first contrib outside LLDB, please let me know if I'm messing up on any of the LLVM style guidelines, idioms, or patterns. Differential Revision: http://reviews.llvm.org/D19746 llvm-svn: 268334 --- llvm/tools/llvm-readobj/COFFDumper.cpp | 164 +++++++++++++++++++++++++-------- 1 file changed, 125 insertions(+), 39 deletions(-) diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index f5ac6e0..a782d2a 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -1866,19 +1866,9 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { } } -StringRef getRemainingTypeBytes(const TypeRecordPrefix *Rec, const char *Start) { - ptrdiff_t StartOffset = Start - reinterpret_cast(Rec); - size_t RecSize = Rec->Len + 2; - assert(StartOffset >= 0 && "negative start-offset!"); - assert(static_cast(StartOffset) <= RecSize && - "Start beyond the end of Rec"); - return StringRef(Start, RecSize - StartOffset); -} - -StringRef getRemainingBytesAsString(const TypeRecordPrefix *Rec, const char *Start) { - StringRef Remaining = getRemainingTypeBytes(Rec, Start); - StringRef Leading, Trailing; - std::tie(Leading, Trailing) = Remaining.split('\0'); +StringRef getLeafDataBytesAsString(StringRef LeafData) { + StringRef Leading; + std::tie(Leading, std::ignore) = LeafData.split('\0'); return Leading; } @@ -1992,47 +1982,148 @@ static StringRef getLeafTypeName(TypeLeafKind LT) { return "UnknownLeaf"; } +// A const input iterator interface to the CodeView type stream. +class CodeViewTypeIterator { +public: + struct TypeRecord { + std::size_t Length; + TypeLeafKind Leaf; + StringRef LeafData; + }; + + explicit CodeViewTypeIterator(const StringRef &SectionData) + : Data(SectionData), AtEnd(false) { + if (Data.size() >= 4) { + Magic = *reinterpret_cast(Data.data()); + Data = Data.drop_front(4); + } + next(); // Prime the pump + } + + CodeViewTypeIterator() : 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 CodeViewTypeIterator &lhs, + const CodeViewTypeIterator &rhs); + + friend bool operator!=(const CodeViewTypeIterator &lhs, + const CodeViewTypeIterator &rhs); + + unsigned getMagic() const { return Magic; } + + const TypeRecord &operator*() const { + assert(!AtEnd); + return Current; + } + + const TypeRecord *operator->() const { + assert(!AtEnd); + return &Current; + } + + CodeViewTypeIterator operator++() { + next(); + return *this; + } + + CodeViewTypeIterator operator++(int) { + CodeViewTypeIterator 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; + } + + const TypeRecordPrefix *Rec; + if (consumeObject(Data, Rec)) + return; + Current.Length = Rec->Len; + Current.Leaf = static_cast(uint16_t(Rec->Leaf)); + Current.LeafData = Data.substr(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; + } + + StringRef Data; + unsigned Magic = 0; + TypeRecord Current; + bool AtEnd; +}; + +bool operator==(const CodeViewTypeIterator &lhs, + const CodeViewTypeIterator &rhs) { + return (lhs.Data.begin() == rhs.Data.begin()) || (lhs.AtEnd && rhs.AtEnd); +} + +bool operator!=(const CodeViewTypeIterator &lhs, + const CodeViewTypeIterator &rhs) { + return !(lhs == rhs); +} + +struct CodeViewTypeStream { + CodeViewTypeIterator begin; + CodeViewTypeIterator end; + unsigned Magic; +}; + +CodeViewTypeStream CreateCodeViewTypeIter(const StringRef &Data) { + CodeViewTypeStream Stream; + Stream.begin = CodeViewTypeIterator(Data); + Stream.end = CodeViewTypeIterator(); + Stream.Magic = Stream.begin.getMagic(); + + return Stream; +} + void COFFDumper::printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section) { ListScope D(W, "CodeViewTypes"); W.printNumber("Section", SectionName, Obj->getSectionID(Section)); + StringRef Data; error(Section.getContents(Data)); if (opts::CodeViewSubsectionBytes) W.printBinaryBlock("Data", Data); - unsigned Magic = *reinterpret_cast(Data.data()); - W.printHex("Magic", Magic); - - Data = Data.drop_front(4); - CVTD.dump(Data); } void CVTypeDumper::dump(StringRef Data) { - while (!Data.empty()) { - const TypeRecordPrefix *Rec; - error(consumeObject(Data, Rec)); - auto Leaf = static_cast(uint16_t(Rec->Leaf)); + CodeViewTypeStream Stream = CreateCodeViewTypeIter(Data); + W.printHex("Magic", Stream.Magic); - // This record is 'Len - 2' bytes, and the next one starts immediately - // afterwards. - StringRef LeafData = Data.substr(0, Rec->Len - 2); - StringRef RemainingData = Data.drop_front(LeafData.size()); + for (auto Iter = Stream.begin; Iter != Stream.end; ++Iter) { + StringRef LeafData = Iter->LeafData; // Find the name of this leaf type. - StringRef LeafName = getLeafTypeName(Leaf); + StringRef LeafName = getLeafTypeName(Iter->Leaf); DictScope S(W, LeafName); unsigned NextTypeIndex = 0x1000 + CVUDTNames.size(); - W.printEnum("TypeLeafKind", unsigned(Leaf), makeArrayRef(LeafTypeNames)); + W.printEnum("TypeLeafKind", unsigned(Iter->Leaf), + makeArrayRef(LeafTypeNames)); W.printHex("TypeIndex", NextTypeIndex); // Fill this in inside the switch to get something in CVUDTNames. StringRef Name; - switch (Leaf) { + switch (Iter->Leaf) { default: { - W.printHex("Size", Rec->Len); + W.printHex("Size", Iter->Length); break; } @@ -2040,7 +2131,7 @@ void CVTypeDumper::dump(StringRef Data) { const StringId *String; error(consumeObject(LeafData, String)); W.printHex("Id", String->id.getIndex()); - StringRef StringData = getRemainingBytesAsString(Rec, LeafData.data()); + StringRef StringData = getLeafDataBytesAsString(LeafData); W.printString("StringData", StringData); // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE. Name = StringData; @@ -2048,7 +2139,7 @@ void CVTypeDumper::dump(StringRef Data) { } case LF_FIELDLIST: { - W.printHex("Size", Rec->Len); + W.printHex("Size", Iter->Length); // FieldList has no fixed prefix that can be described with a struct. All // the bytes must be interpreted as more records. printCodeViewFieldList(LeafData); @@ -2094,7 +2185,7 @@ void CVTypeDumper::dump(StringRef Data) { std::tie(Name, LinkageName) = LeafData.split('\0'); W.printString("Name", Name); if (Props & uint16_t(ClassOptions::HasUniqueName)) { - LinkageName = getRemainingBytesAsString(Rec, LinkageName.data()); + LinkageName = getLeafDataBytesAsString(LinkageName); if (LinkageName.empty()) return error(object_error::parse_failed); W.printString("LinkageName", LinkageName); @@ -2116,7 +2207,7 @@ void CVTypeDumper::dump(StringRef Data) { std::tie(Name, LinkageName) = LeafData.split('\0'); W.printString("Name", Name); if (Props & uint16_t(ClassOptions::HasUniqueName)) { - LinkageName = getRemainingBytesAsString(Rec, LinkageName.data()); + LinkageName = getLeafDataBytesAsString(LinkageName); if (LinkageName.empty()) return error(object_error::parse_failed); W.printString("LinkageName", LinkageName); @@ -2371,11 +2462,6 @@ void CVTypeDumper::dump(StringRef Data) { W.printBinaryBlock("LeafData", LeafData); CVUDTNames.push_back(Name); - - Data = RemainingData; - // 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. } } -- 2.7.4