<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>