<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 2, 2016 at 4:45 PM, Adrian McCarthy via llvm-commits <span dir="ltr"><<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: amccarth<br>
Date: Mon May 2 18:45:03 2016<br>
New Revision: 268334<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=268334&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=268334&view=rev</a><br>
Log:<br>
NFC: An iterator for stepping through CodeView type stream in llvm-readobj<br>
<br>
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.<br>
<br>
The next step is to abstract the parsing of the different leaf types and then move that and the iterator into a library.<br>
<br>
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.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D19746" rel="noreferrer" target="_blank">http://reviews.llvm.org/D19746</a><br>
<br>
Modified:<br>
llvm/trunk/tools/llvm-readobj/COFFDumper.cpp<br>
<br>
Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=268334&r1=268333&r2=268334&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=268334&r1=268333&r2=268334&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)<br>
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Mon May 2 18:45:03 2016<br>
@@ -1866,19 +1866,9 @@ void COFFDumper::printCodeViewInlineeLin<br>
}<br>
}<br>
<br>
-StringRef getRemainingTypeBytes(const TypeRecordPrefix *Rec, const char *Start) {<br>
- ptrdiff_t StartOffset = Start - reinterpret_cast<const char *>(Rec);<br>
- size_t RecSize = Rec->Len + 2;<br>
- assert(StartOffset >= 0 && "negative start-offset!");<br>
- assert(static_cast<size_t>(StartOffset) <= RecSize &&<br>
- "Start beyond the end of Rec");<br>
- return StringRef(Start, RecSize - StartOffset);<br>
-}<br>
-<br>
-StringRef getRemainingBytesAsString(const TypeRecordPrefix *Rec, const char *Start) {<br>
- StringRef Remaining = getRemainingTypeBytes(Rec, Start);<br>
- StringRef Leading, Trailing;<br>
- std::tie(Leading, Trailing) = Remaining.split('\0');<br>
+StringRef getLeafDataBytesAsString(StringRef LeafData) {<br>
+ StringRef Leading;<br>
+ std::tie(Leading, std::ignore) = LeafData.split('\0');<br>
return Leading;<br>
}<br>
<br>
@@ -1992,47 +1982,148 @@ static StringRef getLeafTypeName(TypeLea<br>
return "UnknownLeaf";<br>
}<br>
<br>
+// A const input iterator interface to the CodeView type stream.<br>
+class CodeViewTypeIterator {<br>
+public:<br>
+ struct TypeRecord {<br>
+ std::size_t Length;<br>
+ TypeLeafKind Leaf;<br>
+ StringRef LeafData;<br>
+ };<br>
+<br>
+ explicit CodeViewTypeIterator(const StringRef &SectionData)<br>
+ : Data(SectionData), AtEnd(false) {<br>
+ if (Data.size() >= 4) {<br>
+ Magic = *reinterpret_cast<const ulittle32_t *>(Data.data());<br>
+ Data = Data.drop_front(4);<br>
+ }<br>
+ next(); // Prime the pump<br>
+ }<br>
+<br>
+ CodeViewTypeIterator() : AtEnd(true) {}<br>
+<br>
+ // For iterators to compare equal, they must both point at the same record<br>
+ // in the same data stream, or they must both be at the end of a stream.<br>
+ friend bool operator==(const CodeViewTypeIterator &lhs,<br>
+ const CodeViewTypeIterator &rhs);<br>
+<br>
+ friend bool operator!=(const CodeViewTypeIterator &lhs,<br>
+ const CodeViewTypeIterator &rhs);<br>
+<br>
+ unsigned getMagic() const { return Magic; }<br>
+<br>
+ const TypeRecord &operator*() const {<br>
+ assert(!AtEnd);<br>
+ return Current;<br>
+ }<br>
+<br>
+ const TypeRecord *operator->() const {<br>
+ assert(!AtEnd);<br>
+ return &Current;<br>
+ }<br>
+<br>
+ CodeViewTypeIterator operator++() {<br>
+ next();<br>
+ return *this;<br>
+ }<br>
+<br>
+ CodeViewTypeIterator operator++(int) {<br>
+ CodeViewTypeIterator Original = *this;<br>
+ ++*this;<br>
+ return Original;<br>
+ }<br>
+<br>
+private:<br>
+ void next() {<br>
+ assert(!AtEnd && "Attempted to advance more than one past the last rec");<br>
+ if (Data.empty()) {<br>
+ // We've advanced past the last record.<br>
+ AtEnd = true;<br>
+ return;<br>
+ }<br>
+<br>
+ const TypeRecordPrefix *Rec;<br>
+ if (consumeObject(Data, Rec))<br>
+ return;<br>
+ Current.Length = Rec->Len;<br>
+ Current.Leaf = static_cast<TypeLeafKind>(uint16_t(Rec->Leaf));<br>
+ Current.LeafData = Data.substr(0, Current.Length - 2);<br>
+<br>
+ // The next record starts immediately after this one.<br>
+ Data = Data.drop_front(Current.LeafData.size());<br>
+<br>
+ // FIXME: The stream contains LF_PAD bytes that we need to ignore, but those<br>
+ // are typically included in LeafData. We may need to call skipPadding() if<br>
+ // we ever find a record that doesn't count those bytes.<br>
+<br>
+ return;<br>
+ }<br>
+<br>
+ StringRef Data;<br>
+ unsigned Magic = 0;<br>
+ TypeRecord Current;<br>
+ bool AtEnd;<br>
+};<br>
+<br>
+bool operator==(const CodeViewTypeIterator &lhs,<br>
+ const CodeViewTypeIterator &rhs) {<br>
+ return (lhs.Data.begin() == rhs.Data.begin()) || (lhs.AtEnd && rhs.AtEnd);<br>
+}<br></blockquote><div><br></div><div>If you like, you can still define these operators inline in the class definition, even as non-member friends:<br><br> friend bool operator==(...) {<br> ...<br> }</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+bool operator!=(const CodeViewTypeIterator &lhs,<br>
+ const CodeViewTypeIterator &rhs) {<br>
+ return !(lhs == rhs);<br>
+}<br>
+<br>
+struct CodeViewTypeStream {<br>
+ CodeViewTypeIterator begin;<br>
+ CodeViewTypeIterator end;<br>
+ unsigned Magic;<br>
+};<br>
+<br>
+CodeViewTypeStream CreateCodeViewTypeIter(const StringRef &Data) {<br>
+ CodeViewTypeStream Stream;<br>
+ Stream.begin = CodeViewTypeIterator(Data);<br>
+ Stream.end = CodeViewTypeIterator();<br>
+ Stream.Magic = Stream.begin.getMagic();<br>
+<br>
+ return Stream;<br>
+}<br>
+<br>
void COFFDumper::printCodeViewTypeSection(StringRef SectionName,<br>
const SectionRef &Section) {<br>
ListScope D(W, "CodeViewTypes");<br>
W.printNumber("Section", SectionName, Obj->getSectionID(Section));<br>
+<br>
StringRef Data;<br>
error(Section.getContents(Data));<br>
if (opts::CodeViewSubsectionBytes)<br>
W.printBinaryBlock("Data", Data);<br>
<br>
- unsigned Magic = *reinterpret_cast<const ulittle32_t *>(Data.data());<br>
- W.printHex("Magic", Magic);<br>
-<br>
- Data = Data.drop_front(4);<br>
-<br>
CVTD.dump(Data);<br>
}<br>
<br>
void CVTypeDumper::dump(StringRef Data) {<br>
- while (!Data.empty()) {<br>
- const TypeRecordPrefix *Rec;<br>
- error(consumeObject(Data, Rec));<br>
- auto Leaf = static_cast<TypeLeafKind>(uint16_t(Rec->Leaf));<br>
+ CodeViewTypeStream Stream = CreateCodeViewTypeIter(Data);<br>
+ W.printHex("Magic", Stream.Magic);<br>
<br>
- // This record is 'Len - 2' bytes, and the next one starts immediately<br>
- // afterwards.<br>
- StringRef LeafData = Data.substr(0, Rec->Len - 2);<br>
- StringRef RemainingData = Data.drop_front(LeafData.size());<br>
+ for (auto Iter = Stream.begin; Iter != Stream.end; ++Iter) {<br>
+ StringRef LeafData = Iter->LeafData;<br>
<br>
// Find the name of this leaf type.<br>
- StringRef LeafName = getLeafTypeName(Leaf);<br>
+ StringRef LeafName = getLeafTypeName(Iter->Leaf);<br>
DictScope S(W, LeafName);<br>
unsigned NextTypeIndex = 0x1000 + CVUDTNames.size();<br>
- W.printEnum("TypeLeafKind", unsigned(Leaf), makeArrayRef(LeafTypeNames));<br>
+ W.printEnum("TypeLeafKind", unsigned(Iter->Leaf),<br>
+ makeArrayRef(LeafTypeNames));<br>
W.printHex("TypeIndex", NextTypeIndex);<br>
<br>
// Fill this in inside the switch to get something in CVUDTNames.<br>
StringRef Name;<br>
<br>
- switch (Leaf) {<br>
+ switch (Iter->Leaf) {<br>
default: {<br>
- W.printHex("Size", Rec->Len);<br>
+ W.printHex("Size", Iter->Length);<br>
break;<br>
}<br>
<br>
@@ -2040,7 +2131,7 @@ void CVTypeDumper::dump(StringRef Data)<br>
const StringId *String;<br>
error(consumeObject(LeafData, String));<br>
W.printHex("Id", String->id.getIndex());<br>
- StringRef StringData = getRemainingBytesAsString(Rec, LeafData.data());<br>
+ StringRef StringData = getLeafDataBytesAsString(LeafData);<br>
W.printString("StringData", StringData);<br>
// Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.<br>
Name = StringData;<br>
@@ -2048,7 +2139,7 @@ void CVTypeDumper::dump(StringRef Data)<br>
}<br>
<br>
case LF_FIELDLIST: {<br>
- W.printHex("Size", Rec->Len);<br>
+ W.printHex("Size", Iter->Length);<br>
// FieldList has no fixed prefix that can be described with a struct. All<br>
// the bytes must be interpreted as more records.<br>
printCodeViewFieldList(LeafData);<br>
@@ -2094,7 +2185,7 @@ void CVTypeDumper::dump(StringRef Data)<br>
std::tie(Name, LinkageName) = LeafData.split('\0');<br>
W.printString("Name", Name);<br>
if (Props & uint16_t(ClassOptions::HasUniqueName)) {<br>
- LinkageName = getRemainingBytesAsString(Rec, LinkageName.data());<br>
+ LinkageName = getLeafDataBytesAsString(LinkageName);<br>
if (LinkageName.empty())<br>
return error(object_error::parse_failed);<br>
W.printString("LinkageName", LinkageName);<br>
@@ -2116,7 +2207,7 @@ void CVTypeDumper::dump(StringRef Data)<br>
std::tie(Name, LinkageName) = LeafData.split('\0');<br>
W.printString("Name", Name);<br>
if (Props & uint16_t(ClassOptions::HasUniqueName)) {<br>
- LinkageName = getRemainingBytesAsString(Rec, LinkageName.data());<br>
+ LinkageName = getLeafDataBytesAsString(LinkageName);<br>
if (LinkageName.empty())<br>
return error(object_error::parse_failed);<br>
W.printString("LinkageName", LinkageName);<br>
@@ -2371,11 +2462,6 @@ void CVTypeDumper::dump(StringRef Data)<br>
W.printBinaryBlock("LeafData", LeafData);<br>
<br>
CVUDTNames.push_back(Name);<br>
-<br>
- Data = RemainingData;<br>
- // FIXME: The stream contains LF_PAD bytes that we need to ignore, but those<br>
- // are typically included in LeafData. We may need to call skipPadding() if<br>
- // we ever find a record that doesn't count those bytes.<br>
}<br>
}<br>
<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>