[llvm] r268535 - [codeview] Add a type visitor to help abstract away type stream handling

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Wed May 4 12:39:28 PDT 2016


Author: rnk
Date: Wed May  4 14:39:28 2016
New Revision: 268535

URL: http://llvm.org/viewvc/llvm-project?rev=268535&view=rev
Log:
[codeview] Add a type visitor to help abstract away type stream handling

Summary:
Port the dumper in llvm-readobj over to it.

I'm planning to use this visitor to power type stream merging.

While we're at it, try to switch from StringRef to ArrayRef<uint8_t> in some
places.

Reviewers: zturner, amccarth

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D19899

Added:
    llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def
Modified:
    llvm/trunk/include/llvm/DebugInfo/CodeView/CVLeafTypes.def
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStream.h
    llvm/trunk/include/llvm/Support/ScopedPrinter.h
    llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp
    llvm/trunk/tools/llvm-readobj/COFFDumper.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/CVLeafTypes.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/CVLeafTypes.def?rev=268535&r1=268534&r2=268535&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/CVLeafTypes.def (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVLeafTypes.def Wed May  4 14:39:28 2016
@@ -30,7 +30,7 @@ LEAF_TYPE(LF_UNION_16t, 0x0006)
 LEAF_TYPE(LF_ENUM_16t, 0x0007)
 LEAF_TYPE(LF_PROCEDURE_16t, 0x0008)
 LEAF_TYPE(LF_MFUNCTION_16t, 0x0009)
-LEAF_TYPE(LF_VTSHAPE, 0x000a)
+KNOWN_TYPE(LF_VTSHAPE, 0x000a, VTableShape)
 LEAF_TYPE(LF_COBOL0_16t, 0x000b)
 LEAF_TYPE(LF_COBOL1, 0x000c)
 LEAF_TYPE(LF_BARRAY_16t, 0x000d)
@@ -76,8 +76,8 @@ LEAF_TYPE(LF_VFUNCOFF_16t, 0x040d)
 
 LEAF_TYPE(LF_TI16_MAX, 0x1000)
 
-LEAF_TYPE(LF_MODIFIER, 0x1001)
-LEAF_TYPE(LF_POINTER, 0x1002)
+KNOWN_TYPE(LF_MODIFIER, 0x1001, TypeModifier)
+KNOWN_TYPE(LF_POINTER, 0x1002, PointerType)
 LEAF_TYPE(LF_ARRAY_ST, 0x1003)
 LEAF_TYPE(LF_CLASS_ST, 0x1004)
 LEAF_TYPE(LF_STRUCTURE_ST, 0x1005)

Added: llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h?rev=268535&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h Wed May  4 14:39:28 2016
@@ -0,0 +1,153 @@
+//===- CVTypeVisitor.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_CVTYPEVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeStream.h"
+
+namespace llvm {
+namespace codeview {
+
+template <typename Derived>
+class CVTypeVisitor {
+public:
+  CVTypeVisitor() {}
+
+  bool hadError() const { return HadError; }
+
+  template <typename T>
+  bool consumeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
+    if (Data.size() < sizeof(*Res)) {
+      HadError = true;
+      return false;
+    }
+    Res = reinterpret_cast<const T *>(Data.data());
+    Data = Data.drop_front(sizeof(*Res));
+    return true;
+  }
+
+  /// Actions to take on known types. By default, they do nothing. Visit methods
+  /// for member records take the FieldData by non-const reference and are
+  /// expected to consume the trailing bytes used by the field.
+  /// FIXME: Make the visitor interpret the trailing bytes so that clients don't
+  /// need to.
+#define TYPE_RECORD(ClassName, LeafEnum)                                       \
+  void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record,        \
+                        ArrayRef<uint8_t> LeafData) {}
+#define TYPE_RECORD_ALIAS(ClassName, LeafEnum)
+#define MEMBER_RECORD(ClassName, LeafEnum)                                     \
+  void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record,        \
+                        ArrayRef<uint8_t> &FieldData) {}
+#define MEMBER_RECORD_ALIAS(ClassName, LeafEnum)
+#include "TypeRecords.def"
+
+  /// Visits the type records in Data and returns remaining data. Sets the
+  /// error flag on parse failures.
+  void visitTypeStream(ArrayRef<uint8_t> Data) {
+    for (const auto &I : makeTypeRange(Data)) {
+      ArrayRef<uint8_t> LeafData = I.LeafData;
+      ArrayRef<uint8_t> RecordData = LeafData;
+      auto *DerivedThis = static_cast<Derived *>(this);
+      DerivedThis->visitTypeBegin(I.Leaf, RecordData);
+      switch (I.Leaf) {
+      default:
+        DerivedThis->visitUnknownType(I.Leaf);
+        break;
+      case LF_FIELDLIST:
+        DerivedThis->visitFieldList(I.Leaf, LeafData);
+        break;
+      case LF_METHODLIST:
+        DerivedThis->visitMethodList(I.Leaf, LeafData);
+        break;
+#define TYPE_RECORD(ClassName, LeafEnum)                                       \
+  case LeafEnum: {                                                             \
+    const ClassName *Rec;                                                      \
+    if (!CVTypeVisitor::consumeObject(LeafData, Rec))                          \
+      return;                                                                  \
+    DerivedThis->visit##ClassName(I.Leaf, Rec, LeafData);     \
+    break;                                                                     \
+  }
+#include "TypeRecords.def"
+      }
+      DerivedThis->visitTypeEnd(I.Leaf, RecordData);
+    }
+  }
+
+  /// Action to take on unknown types. By default, they are ignored.
+  void visitUnknownType(TypeLeafKind Leaf) {}
+
+  /// Paired begin/end actions for all types. Receives all record data,
+  /// including the fixed-length record prefix.
+  void visitTypeBegin(TypeLeafKind Leaf, ArrayRef<uint8_t> RecordData) {}
+  void visitTypeEnd(TypeLeafKind Leaf, ArrayRef<uint8_t> RecordData) {}
+
+  static ArrayRef<uint8_t> skipPadding(ArrayRef<uint8_t> Data) {
+    if (Data.empty())
+      return Data;
+    uint8_t Leaf = Data.front();
+    if (Leaf < LF_PAD0)
+      return Data;
+    // Leaf is greater than 0xf0. We should advance by the number of bytes in
+    // the low 4 bits.
+    return Data.drop_front(Leaf & 0x0F);
+  }
+
+  /// Visits individual member records of a field list record. Member records do
+  /// not describe their own length, and need special handling.
+  void visitFieldList(TypeLeafKind Leaf, ArrayRef<uint8_t> FieldData) {
+    while (!FieldData.empty()) {
+      const ulittle16_t *LeafPtr;
+      if (!CVTypeVisitor::consumeObject(FieldData, LeafPtr))
+        return;
+      TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr));
+      switch (Leaf) {
+      default:
+        // Field list records do not describe their own length, so we cannot
+        // continue parsing past an unknown member type.
+        visitUnknownMember(Leaf);
+        HadError = true;
+        return;
+#define MEMBER_RECORD(ClassName, LeafEnum)                                     \
+  case LeafEnum: {                                                             \
+    const ClassName *Rec;                                                      \
+    if (!CVTypeVisitor::consumeObject(FieldData, Rec))                         \
+      return;                                                                  \
+    static_cast<Derived *>(this)->visit##ClassName(Leaf, Rec, FieldData);      \
+    break;                                                                     \
+  }
+#include "TypeRecords.def"
+      }
+      FieldData = skipPadding(FieldData);
+    }
+  }
+
+  /// Action to take on method overload lists, which do not have a common record
+  /// prefix. The LeafData is composed of MethodListEntry objects, each of which
+  /// may have a trailing 32-bit vftable offset.
+  /// FIXME: Hoist this complexity into the visitor.
+  void visitMethodList(TypeLeafKind Leaf, ArrayRef<uint8_t> LeafData) {}
+
+  /// Action to take on unknown members. By default, they are ignored. Member
+  /// record parsing cannot recover from an unknown member record, so this
+  /// method is only called at most once per field list record.
+  void visitUnknownMember(TypeLeafKind Leaf) {}
+
+private:
+  /// Whether a type stream parsing error was encountered.
+  bool HadError = false;
+};
+
+} // end namespace codeview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H

Added: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def?rev=268535&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def (added)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def Wed May  4 14:39:28 2016
@@ -0,0 +1,75 @@
+
+//===-- CVLeafTypes.def - All CodeView leaf types ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// See LEAF_ENUM_e in cvinfo.h. This should match the constants there.
+//
+//===----------------------------------------------------------------------===//
+
+// If the type is known, then we have a record describing it in TypeRecord.h.
+#ifndef TYPE_RECORD
+#define TYPE_RECORD(ClassName, LeafEnum)
+#endif
+
+#ifndef TYPE_RECORD_ALIAS
+#define TYPE_RECORD_ALIAS(ClassName, LeafEnum) TYPE_RECORD(ClassName, LeafEnum)
+#endif
+
+#ifndef MEMBER_RECORD
+#define MEMBER_RECORD(ClassName, LeafEnum) TYPE_RECORD(ClassName, LeafEnum)
+#endif
+
+#ifndef MEMBER_RECORD_ALIAS
+#define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) MEMBER_RECORD(ClassName, LeafEnum)
+#endif
+
+
+TYPE_RECORD(PointerType, LF_POINTER)
+TYPE_RECORD(TypeModifier, LF_MODIFIER)
+TYPE_RECORD(ProcedureType, LF_PROCEDURE)
+TYPE_RECORD(MemberFunctionType, LF_MFUNCTION)
+TYPE_RECORD(ArgList, LF_ARGLIST)
+
+TYPE_RECORD(ArrayType, LF_ARRAY)
+TYPE_RECORD(ClassType, LF_CLASS)
+TYPE_RECORD_ALIAS(ClassType, LF_STRUCTURE)
+TYPE_RECORD_ALIAS(ClassType, LF_INTERFACE)
+TYPE_RECORD(UnionType, LF_UNION)
+TYPE_RECORD(EnumType, LF_ENUM)
+TYPE_RECORD(TypeServer2, LF_TYPESERVER2)
+TYPE_RECORD(VFTableType, LF_VFTABLE)
+TYPE_RECORD(VTableShape, LF_VTSHAPE)
+
+// Member type records. These are generally not length prefixed, and appear
+// inside of a field list record.
+MEMBER_RECORD(BaseClass, LF_BCLASS)
+MEMBER_RECORD_ALIAS(BaseClass, LF_BINTERFACE)
+MEMBER_RECORD(VirtualBaseClass, LF_VBCLASS)
+MEMBER_RECORD_ALIAS(VirtualBaseClass, LF_IVBCLASS)
+MEMBER_RECORD(VirtualFunctionPointer, LF_VFUNCTAB)
+MEMBER_RECORD(StaticDataMember, LF_STMEMBER)
+MEMBER_RECORD(OverloadedMethod, LF_METHOD)
+MEMBER_RECORD(DataMember, LF_MEMBER)
+MEMBER_RECORD(NestedType, LF_NESTTYPE)
+MEMBER_RECORD(OneMethod, LF_ONEMETHOD)
+MEMBER_RECORD(Enumerator, LF_ENUMERATE)
+
+// ID leaf records. Subsequent leaf types may be referenced from .debug$S.
+
+TYPE_RECORD(FuncId, LF_FUNC_ID)
+TYPE_RECORD(MemberFuncId, LF_MFUNC_ID)
+TYPE_RECORD(BuildInfo, LF_BUILDINFO)
+TYPE_RECORD_ALIAS(ArgList, LF_SUBSTR_LIST)
+TYPE_RECORD(StringId, LF_STRING_ID)
+TYPE_RECORD(UDTSrcLine, LF_UDT_SRC_LINE)
+
+#undef TYPE_RECORD
+#undef TYPE_RECORD_ALIAS
+#undef MEMBER_RECORD
+#undef MEMBER_RECORD_ALIAS

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStream.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStream.h?rev=268535&r1=268534&r2=268535&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStream.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeStream.h Wed May  4 14:39:28 2016
@@ -49,10 +49,10 @@ public:
   struct TypeRecord {
     std::size_t Length;
     TypeLeafKind Leaf;
-    StringRef LeafData;
+    ArrayRef<uint8_t> LeafData;
   };
 
-  explicit TypeIterator(const StringRef &SectionData)
+  explicit TypeIterator(const ArrayRef<uint8_t> &SectionData)
       : Data(SectionData), AtEnd(false) {
     next(); // Prime the pump
   }
@@ -99,12 +99,15 @@ private:
       return;
     }
 
-    const TypeRecordPrefix *Rec;
-    if (consumeObject(Data, Rec))
+    // FIXME: Use consumeObject when it deals in ArrayRef<uint8_t>.
+    if (Data.size() < sizeof(TypeRecordPrefix))
       return;
+    const auto *Rec = reinterpret_cast<const TypeRecordPrefix *>(Data.data());
+    Data = Data.drop_front(sizeof(TypeRecordPrefix));
+
     Current.Length = Rec->Len;
     Current.Leaf = static_cast<TypeLeafKind>(uint16_t(Rec->Leaf));
-    Current.LeafData = Data.substr(0, Current.Length - 2);
+    Current.LeafData = Data.slice(0, Current.Length - 2);
 
     // The next record starts immediately after this one.
     Data = Data.drop_front(Current.LeafData.size());
@@ -116,15 +119,16 @@ private:
     return;
   }
 
-  StringRef Data;
+  ArrayRef<uint8_t> Data;
   TypeRecord Current;
   bool AtEnd;
 };
 
-inline iterator_range<TypeIterator> makeTypeRange(StringRef Data) {
+inline iterator_range<TypeIterator> makeTypeRange(ArrayRef<uint8_t> Data) {
   return make_range(TypeIterator(Data), TypeIterator());
 }
-}
-}
+
+} // end namespace codeview
+} // end namespace llvm
 
 #endif

Modified: llvm/trunk/include/llvm/Support/ScopedPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ScopedPrinter.h?rev=268535&r1=268534&r2=268535&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/ScopedPrinter.h (original)
+++ llvm/trunk/include/llvm/Support/ScopedPrinter.h Wed May  4 14:39:28 2016
@@ -277,6 +277,10 @@ public:
     printBinaryImpl(Label, StringRef(), V, false);
   }
 
+  void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
+    printBinaryImpl(Label, StringRef(), Value, true);
+  }
+
   void printBinaryBlock(StringRef Label, StringRef Value) {
     auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
                           Value.size());

Modified: llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp?rev=268535&r1=268534&r2=268535&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp Wed May  4 14:39:28 2016
@@ -116,5 +116,5 @@ uint32_t TpiStream::NumTypeRecords() con
 }
 
 iterator_range<codeview::TypeIterator> TpiStream::types() const {
-  return codeview::makeTypeRange(RecordsBuffer.str());
+  return codeview::makeTypeRange(RecordsBuffer.data());
 }

Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=268535&r1=268534&r2=268535&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Wed May  4 14:39:28 2016
@@ -23,6 +23,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/Line.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
@@ -53,21 +54,53 @@ using namespace llvm::Win64EH;
 
 namespace {
 
-class CVTypeDumper {
+class CVTypeDumper : public CVTypeVisitor<CVTypeDumper> {
 public:
   CVTypeDumper(ScopedPrinter &W) : W(W) {}
 
   StringRef getTypeName(TypeIndex TI);
   void printTypeIndex(StringRef FieldName, TypeIndex TI);
 
-  void dump(StringRef Data);
+  void dump(ArrayRef<uint8_t> Data);
+
+  /// CVTypeVisitor overrides.
+#define TYPE_RECORD(ClassName, LeafEnum)                                       \
+  void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record,        \
+                        ArrayRef<uint8_t> LeafData);
+#define TYPE_RECORD_ALIAS(ClassName, LeafEnum)
+#define MEMBER_RECORD(ClassName, LeafEnum)                                     \
+  void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record,        \
+                        ArrayRef<uint8_t> &FieldData);
+#define MEMBER_RECORD_ALIAS(ClassName, LeafEnum)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+
+  /// Method overload lists are a special case.
+  void visitMethodList(TypeLeafKind Leaf, ArrayRef<uint8_t> LeafData);
+
+  void visitUnknownMember(TypeLeafKind Leaf);
+
+  void visitTypeBegin(TypeLeafKind Leaf, ArrayRef<uint8_t> LeafData);
+  void visitTypeEnd(TypeLeafKind Leaf, ArrayRef<uint8_t> LeafData);
 
 private:
-  void printCodeViewFieldList(StringRef FieldData);
   void printMemberAttributes(MemberAttributes Attrs);
 
+  /// Reinterpret a byte array as an array of characters. Does not interpret as
+  /// a C string, as StringRef has several helpers (split) that make that easy.
+  static StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
+    return StringRef(reinterpret_cast<const char *>(LeafData.data()),
+                     LeafData.size());
+  }
+
+  static StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData) {
+    return getBytesAsCharacters(LeafData).split('\0').first;
+  }
+
   ScopedPrinter &W;
 
+  /// Name of the current type. Only valid before visitTypeEnd.
+  StringRef Name;
+
   /// All user defined type records in .debug$T live in here. Type indices
   /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to
   /// index into this vector.
@@ -1181,7 +1214,8 @@ void COFFDumper::printCodeViewSymbolSect
   }
 }
 
-static std::error_code decodeNumerictLeaf(StringRef &Data, APSInt &Num) {
+static std::error_code decodeNumerictLeaf(ArrayRef<uint8_t> &Data,
+                                          APSInt &Num) {
   // Used to avoid overload ambiguity on APInt construtor.
   bool FalseVal = false;
   if (Data.size() < 2)
@@ -1247,8 +1281,16 @@ static std::error_code decodeNumerictLea
   return object_error::parse_failed;
 }
 
+static std::error_code decodeNumerictLeaf(StringRef &Data, APSInt &Num) {
+  ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(Data.data()),
+                          Data.size());
+  auto EC = decodeNumerictLeaf(Bytes, Num);
+  Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+  return EC;
+}
+
 /// Decode an unsigned integer numeric leaf value.
-std::error_code decodeUIntLeaf(StringRef &Data, uint64_t &Num) {
+std::error_code decodeUIntLeaf(ArrayRef<uint8_t> &Data, uint64_t &Num) {
   APSInt N;
   if (std::error_code err = decodeNumerictLeaf(Data, N))
     return err;
@@ -1847,12 +1889,6 @@ void COFFDumper::printCodeViewInlineeLin
   }
 }
 
-StringRef getLeafDataBytesAsString(StringRef LeafData) {
-  StringRef Leading;
-  std::tie(Leading, std::ignore) = LeafData.split('\0');
-  return Leading;
-}
-
 StringRef CVTypeDumper::getTypeName(TypeIndex TI) {
   if (TI.isNoType())
     return "<no type>";
@@ -1945,7 +1981,6 @@ static StringRef getLeafTypeName(TypeLea
   return "UnknownLeaf";
 }
 
-
 void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
                                           const SectionRef &Section) {
   ListScope D(W, "CodeViewTypes");
@@ -1955,384 +1990,340 @@ void COFFDumper::printCodeViewTypeSectio
   error(Section.getContents(Data));
   if (opts::CodeViewSubsectionBytes)
     W.printBinaryBlock("Data", Data);
-  CVTD.dump(Data);
-}
 
-void CVTypeDumper::dump(StringRef Data) {
   uint32_t Magic;
-  if (consumeUInt32(Data, Magic))
-    return;
-  if (Magic != COFF::DEBUG_SECTION_MAGIC)
-    return;
-
+  error(consumeUInt32(Data, Magic));
   W.printHex("Magic", Magic);
-  for (const auto &Record : makeTypeRange(Data)) {
-    StringRef LeafData = Record.LeafData;
-
-    // Find the name of this leaf type.
-    StringRef LeafName = getLeafTypeName(Record.Leaf);
-    DictScope S(W, LeafName);
-    unsigned NextTypeIndex = 0x1000 + CVUDTNames.size();
-    W.printEnum("TypeLeafKind", unsigned(Record.Leaf),
-                makeArrayRef(LeafTypeNames));
-    W.printHex("TypeIndex", NextTypeIndex);
-
-    // Fill this in inside the switch to get something in CVUDTNames.
-    StringRef Name;
-
-    switch (Record.Leaf) {
-    default: {
-      W.printHex("Size", Record.Length);
-      break;
-    }
-
-    case LF_STRING_ID: {
-      const StringId *String;
-      error(consumeObject(LeafData, String));
-      W.printHex("Id", String->id.getIndex());
-      StringRef StringData = getLeafDataBytesAsString(LeafData);
-      W.printString("StringData", StringData);
-      // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
-      Name = StringData;
-      break;
-    }
-
-    case LF_FIELDLIST: {
-      W.printHex("Size", Record.Length);
-      // FieldList has no fixed prefix that can be described with a struct. All
-      // the bytes must be interpreted as more records.
-      printCodeViewFieldList(LeafData);
-      break;
-    }
-
-    case LF_ARGLIST:
-    case LF_SUBSTR_LIST: {
-      const ArgList *Args;
-      error(consumeObject(LeafData, Args));
-      W.printNumber("NumArgs", Args->NumArgs);
-      ListScope Arguments(W, "Arguments");
-      SmallString<256> TypeName("(");
-      for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) {
-        const TypeIndex *Type;
-        error(consumeObject(LeafData, Type));
-        printTypeIndex("ArgType", *Type);
-        StringRef ArgTypeName = getTypeName(*Type);
-        TypeName.append(ArgTypeName);
-        if (ArgI + 1 != Args->NumArgs)
-          TypeName.append(", ");
-      }
-      TypeName.push_back(')');
-      Name = TypeNames.insert(TypeName).first->getKey();
-      break;
-    }
-
-    case LF_CLASS:
-    case LF_STRUCTURE:
-    case LF_INTERFACE: {
-      const ClassType *Class;
-      error(consumeObject(LeafData, Class));
-      W.printNumber("MemberCount", Class->MemberCount);
-      uint16_t Props = Class->Properties;
-      W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
-      printTypeIndex("FieldList", Class->FieldList);
-      printTypeIndex("DerivedFrom", Class->DerivedFrom);
-      printTypeIndex("VShape", Class->VShape);
-      uint64_t SizeOf;
-      error(decodeUIntLeaf(LeafData, SizeOf));
-      W.printNumber("SizeOf", SizeOf);
-      StringRef LinkageName;
-      std::tie(Name, LinkageName) = LeafData.split('\0');
-      W.printString("Name", Name);
-      if (Props & uint16_t(ClassOptions::HasUniqueName)) {
-        LinkageName = getLeafDataBytesAsString(LinkageName);
-        if (LinkageName.empty())
-          return error(object_error::parse_failed);
-        W.printString("LinkageName", LinkageName);
-      }
-      break;
-    }
-
-    case LF_UNION: {
-      const UnionType *Union;
-      error(consumeObject(LeafData, Union));
-      W.printNumber("MemberCount", Union->MemberCount);
-      uint16_t Props = Union->Properties;
-      W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
-      printTypeIndex("FieldList", Union->FieldList);
-      uint64_t SizeOf;
-      error(decodeUIntLeaf(LeafData, SizeOf));
-      W.printNumber("SizeOf", SizeOf);
-      StringRef LinkageName;
-      std::tie(Name, LinkageName) = LeafData.split('\0');
-      W.printString("Name", Name);
-      if (Props & uint16_t(ClassOptions::HasUniqueName)) {
-        LinkageName = getLeafDataBytesAsString(LinkageName);
-        if (LinkageName.empty())
-          return error(object_error::parse_failed);
-        W.printString("LinkageName", LinkageName);
-      }
-      break;
-    }
-
-    case LF_ENUM: {
-      const EnumType *Enum;
-      error(consumeObject(LeafData, Enum));
-      W.printNumber("NumEnumerators", Enum->NumEnumerators);
-      W.printFlags("Properties", uint16_t(Enum->Properties),
-                   makeArrayRef(ClassOptionNames));
-      printTypeIndex("UnderlyingType", Enum->UnderlyingType);
-      printTypeIndex("FieldListType", Enum->FieldListType);
-      Name = LeafData.split('\0').first;
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_ARRAY: {
-      const ArrayType *AT;
-      error(consumeObject(LeafData, AT));
-      printTypeIndex("ElementType", AT->ElementType);
-      printTypeIndex("IndexType", AT->IndexType);
-      uint64_t SizeOf;
-      error(decodeUIntLeaf(LeafData, SizeOf));
-      W.printNumber("SizeOf", SizeOf);
-      Name = LeafData.split('\0').first;
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_VFTABLE: {
-      const VFTableType *VFT;
-      error(consumeObject(LeafData, VFT));
-      printTypeIndex("CompleteClass", VFT->CompleteClass);
-      printTypeIndex("OverriddenVFTable", VFT->OverriddenVFTable);
-      W.printHex("VFPtrOffset", VFT->VFPtrOffset);
-      StringRef NamesData = LeafData.substr(0, VFT->NamesLen);
-      std::tie(Name, NamesData) = NamesData.split('\0');
-      W.printString("VFTableName", Name);
-      while (!NamesData.empty()) {
-        StringRef MethodName;
-        std::tie(MethodName, NamesData) = NamesData.split('\0');
-        W.printString("MethodName", MethodName);
-      }
-      break;
-    }
-
-    case LF_MFUNC_ID: {
-      const MemberFuncId *Id;
-      error(consumeObject(LeafData, Id));
-      printTypeIndex("ClassType", Id->ClassType);
-      printTypeIndex("FunctionType", Id->FunctionType);
-      Name = LeafData.split('\0').first;
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_PROCEDURE: {
-      const ProcedureType *Proc;
-      error(consumeObject(LeafData, Proc));
-      printTypeIndex("ReturnType", Proc->ReturnType);
-      W.printEnum("CallingConvention", uint8_t(Proc->CallConv),
-                  makeArrayRef(CallingConventions));
-      W.printFlags("FunctionOptions", uint8_t(Proc->Options),
-                   makeArrayRef(FunctionOptionEnum));
-      W.printNumber("NumParameters", Proc->NumParameters);
-      printTypeIndex("ArgListType", Proc->ArgListType);
-
-      StringRef ReturnTypeName = getTypeName(Proc->ReturnType);
-      StringRef ArgListTypeName = getTypeName(Proc->ArgListType);
-      SmallString<256> TypeName(ReturnTypeName);
-      TypeName.push_back(' ');
-      TypeName.append(ArgListTypeName);
-      Name = TypeNames.insert(TypeName).first->getKey();
-      break;
-    }
-
-    case LF_MFUNCTION: {
-      const MemberFunctionType *MemberFunc;
-      error(consumeObject(LeafData, MemberFunc));
-      printTypeIndex("ReturnType", MemberFunc->ReturnType);
-      printTypeIndex("ClassType", MemberFunc->ClassType);
-      printTypeIndex("ThisType", MemberFunc->ThisType);
-      W.printEnum("CallingConvention", uint8_t(MemberFunc->CallConv),
-                  makeArrayRef(CallingConventions));
-      W.printFlags("FunctionOptions", uint8_t(MemberFunc->Options),
-                   makeArrayRef(FunctionOptionEnum));
-      W.printNumber("NumParameters", MemberFunc->NumParameters);
-      printTypeIndex("ArgListType", MemberFunc->ArgListType);
-      W.printNumber("ThisAdjustment", MemberFunc->ThisAdjustment);
-
-      StringRef ReturnTypeName = getTypeName(MemberFunc->ReturnType);
-      StringRef ClassTypeName = getTypeName(MemberFunc->ClassType);
-      StringRef ArgListTypeName = getTypeName(MemberFunc->ArgListType);
-      SmallString<256> TypeName(ReturnTypeName);
-      TypeName.push_back(' ');
-      TypeName.append(ClassTypeName);
-      TypeName.append("::");
-      TypeName.append(ArgListTypeName);
-      Name = TypeNames.insert(TypeName).first->getKey();
-      break;
-    }
+  if (Magic != COFF::DEBUG_SECTION_MAGIC)
+    return error(object_error::parse_failed);
 
-    case LF_METHODLIST: {
-      while (!LeafData.empty()) {
-        const MethodListEntry *Method;
-        error(consumeObject(LeafData, Method));
-        ListScope S(W, "Method");
-        printMemberAttributes(Method->Attrs);
-        printTypeIndex("Type", Method->Type);
-        if (Method->isIntroducedVirtual()) {
-          const little32_t *VFTOffsetPtr;
-          error(consumeObject(LeafData, VFTOffsetPtr));
-          W.printHex("VFTableOffset", *VFTOffsetPtr);
-        }
-      }
-      break;
-    }
+  ArrayRef<uint8_t> BinaryData(reinterpret_cast<const uint8_t *>(Data.data()),
+                               Data.size());
+  CVTD.dump(BinaryData);
+}
 
-    case LF_FUNC_ID: {
-      const FuncId *Func;
-      error(consumeObject(LeafData, Func));
-      printTypeIndex("ParentScope", Func->ParentScope);
-      printTypeIndex("FunctionType", Func->FunctionType);
-      StringRef Null;
-      std::tie(Name, Null) = LeafData.split('\0');
-      W.printString("Name", Name);
-      break;
-    }
+void CVTypeDumper::dump(ArrayRef<uint8_t> Data) {
+  visitTypeStream(Data);
+  if (hadError())
+    error(object_error::parse_failed);
+}
 
-    case LF_TYPESERVER2: {
-      const TypeServer2 *TypeServer;
-      error(consumeObject(LeafData, TypeServer));
-      W.printBinary("Signature", StringRef(TypeServer->Signature, 16));
-      W.printNumber("Age", TypeServer->Age);
-      Name = LeafData.split('\0').first;
-      W.printString("Name", Name);
-      break;
-    }
+void CVTypeDumper::visitTypeBegin(TypeLeafKind Leaf, ArrayRef<uint8_t> LeafData) {
+  // Reset Name to the empty string. If the visitor sets it, we know it.
+  Name = "";
+
+  W.startLine() << getLeafTypeName(Leaf) << " {\n";
+  W.indent();
+  unsigned NextTypeIndex = 0x1000 + CVUDTNames.size();
+  W.printEnum("TypeLeafKind", unsigned(Leaf), makeArrayRef(LeafTypeNames));
+  W.printHex("TypeIndex", NextTypeIndex);
+  W.flush();
+}
 
-    case LF_POINTER: {
-      const PointerType *Ptr;
-      error(consumeObject(LeafData, Ptr));
-      printTypeIndex("PointeeType", Ptr->PointeeType);
-      W.printHex("PointerAttributes", Ptr->Attrs);
-      W.printEnum("PtrType", unsigned(Ptr->getPtrKind()),
-                  makeArrayRef(PtrKindNames));
-      W.printEnum("PtrMode", unsigned(Ptr->getPtrMode()),
-                  makeArrayRef(PtrModeNames));
-      W.printNumber("IsFlat", Ptr->isFlat());
-      W.printNumber("IsConst", Ptr->isConst());
-      W.printNumber("IsVolatile", Ptr->isVolatile());
-      W.printNumber("IsUnaligned", Ptr->isUnaligned());
-
-      if (Ptr->isPointerToMember()) {
-        const PointerToMemberTail *PMT;
-        error(consumeObject(LeafData, PMT));
-        printTypeIndex("ClassType", PMT->ClassType);
-        W.printEnum("Representation", PMT->Representation,
-                    makeArrayRef(PtrMemberRepNames));
-
-        StringRef PointeeName = getTypeName(Ptr->PointeeType);
-        StringRef ClassName = getTypeName(PMT->ClassType);
-        SmallString<256> TypeName(PointeeName);
-        TypeName.push_back(' ');
-        TypeName.append(ClassName);
-        TypeName.append("::*");
-        Name = TypeNames.insert(TypeName).first->getKey();
-      } else {
-        W.printBinaryBlock("TailData", LeafData);
-
-        SmallString<256> TypeName;
-        if (Ptr->isConst())
-          TypeName.append("const ");
-        if (Ptr->isVolatile())
-          TypeName.append("volatile ");
-        if (Ptr->isUnaligned())
-          TypeName.append("__unaligned ");
-
-        TypeName.append(getTypeName(Ptr->PointeeType));
-
-        if (Ptr->getPtrMode() == PointerMode::LValueReference)
-          TypeName.append("&");
-        else if (Ptr->getPtrMode() == PointerMode::RValueReference)
-          TypeName.append("&&");
-        else if (Ptr->getPtrMode() == PointerMode::Pointer)
-          TypeName.append("*");
+void CVTypeDumper::visitTypeEnd(TypeLeafKind Leaf, ArrayRef<uint8_t> LeafData) {
+  // Always record some name for every type, even if Name is empty, since
+  // CVUDTNames is indexed by TypeIndex.
+  CVUDTNames.push_back(Name);
 
-        Name = TypeNames.insert(TypeName).first->getKey();
-      }
-      break;
-    }
+  if (opts::CodeViewSubsectionBytes)
+    W.printBinaryBlock("LeafData", getBytesAsCharacters(LeafData));
 
-    case LF_MODIFIER: {
-      const TypeModifier *Mod;
-      error(consumeObject(LeafData, Mod));
-      printTypeIndex("ModifiedType", Mod->ModifiedType);
-      W.printFlags("Modifiers", Mod->Modifiers,
-                   makeArrayRef(TypeModifierNames));
-
-      StringRef ModifiedName = getTypeName(Mod->ModifiedType);
-      SmallString<256> TypeName;
-      if (Mod->Modifiers & uint16_t(ModifierOptions::Const))
-        TypeName.append("const ");
-      if (Mod->Modifiers & uint16_t(ModifierOptions::Volatile))
-        TypeName.append("volatile ");
-      if (Mod->Modifiers & uint16_t(ModifierOptions::Unaligned))
-        TypeName.append("__unaligned ");
-      TypeName.append(ModifiedName);
-      Name = TypeNames.insert(TypeName).first->getKey();
-      break;
-    }
+  W.unindent();
+  W.startLine() << "}\n";
+  W.flush();
+}
 
-    case LF_VTSHAPE: {
-      const VTableShape *Shape;
-      error(consumeObject(LeafData, Shape));
-      unsigned VFEntryCount = Shape->VFEntryCount;
-      W.printNumber("VFEntryCount", VFEntryCount);
-      // We could print out whether the methods are near or far, but in practice
-      // today everything is CV_VTS_near32, so it's just noise.
-      break;
-    }
+void CVTypeDumper::visitStringId(TypeLeafKind Leaf, const StringId *String,
+                                 ArrayRef<uint8_t> LeafData) {
+  W.printHex("Id", String->id.getIndex());
+  StringRef StringData = getBytesAsCString(LeafData);
+  W.printString("StringData", StringData);
+  // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
+  Name = StringData;
+}
+
+void CVTypeDumper::visitArgList(TypeLeafKind Leaf, const ArgList *Args,
+                                ArrayRef<uint8_t> LeafData) {
+  W.printNumber("NumArgs", Args->NumArgs);
+  ListScope Arguments(W, "Arguments");
+  SmallString<256> TypeName("(");
+  for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) {
+    const TypeIndex *Type;
+    if (!consumeObject(LeafData, Type))
+      return;
+    printTypeIndex("ArgType", *Type);
+    StringRef ArgTypeName = getTypeName(*Type);
+    TypeName.append(ArgTypeName);
+    if (ArgI + 1 != Args->NumArgs)
+      TypeName.append(", ");
+  }
+  TypeName.push_back(')');
+  Name = TypeNames.insert(TypeName).first->getKey();
+}
+
+void CVTypeDumper::visitClassType(TypeLeafKind Leaf, const ClassType *Class,
+                                  ArrayRef<uint8_t> LeafData) {
+  W.printNumber("MemberCount", Class->MemberCount);
+  uint16_t Props = Class->Properties;
+  W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+  printTypeIndex("FieldList", Class->FieldList);
+  printTypeIndex("DerivedFrom", Class->DerivedFrom);
+  printTypeIndex("VShape", Class->VShape);
+  uint64_t SizeOf;
+  error(decodeUIntLeaf(LeafData, SizeOf));
+  W.printNumber("SizeOf", SizeOf);
+  StringRef LeafChars = getBytesAsCharacters(LeafData);
+  StringRef LinkageName;
+  std::tie(Name, LinkageName) = LeafChars.split('\0');
+  W.printString("Name", Name);
+  if (Props & uint16_t(ClassOptions::HasUniqueName)) {
+    LinkageName = LinkageName.split('\0').first;
+    if (LinkageName.empty())
+      return error(object_error::parse_failed);
+    W.printString("LinkageName", LinkageName);
+  }
+}
 
-    case LF_UDT_SRC_LINE: {
-      const UDTSrcLine *Line;
-      error(consumeObject(LeafData, Line));
-      printTypeIndex("UDT", Line->UDT);
-      printTypeIndex("SourceFile", Line->SourceFile);
-      W.printNumber("LineNumber", Line->LineNumber);
-      break;
-    }
+void CVTypeDumper::visitUnionType(TypeLeafKind Leaf, const UnionType *Union,
+                                  ArrayRef<uint8_t> LeafData) {
+  W.printNumber("MemberCount", Union->MemberCount);
+  uint16_t Props = Union->Properties;
+  W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+  printTypeIndex("FieldList", Union->FieldList);
+  uint64_t SizeOf;
+  error(decodeUIntLeaf(LeafData, SizeOf));
+  W.printNumber("SizeOf", SizeOf);
+  StringRef LeafChars = getBytesAsCharacters(LeafData);
+  StringRef LinkageName;
+  std::tie(Name, LinkageName) = LeafChars.split('\0');
+  W.printString("Name", Name);
+  if (Props & uint16_t(ClassOptions::HasUniqueName)) {
+    LinkageName = LinkageName.split('\0').first;
+    if (LinkageName.empty())
+      return error(object_error::parse_failed);
+    W.printString("LinkageName", LinkageName);
+  }
+}
 
-    case LF_BUILDINFO: {
-      const BuildInfo *Args;
-      error(consumeObject(LeafData, Args));
-      W.printNumber("NumArgs", Args->NumArgs);
-
-      ListScope Arguments(W, "Arguments");
-      for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) {
-        const TypeIndex *Type;
-        error(consumeObject(LeafData, Type));
-        printTypeIndex("ArgType", *Type);
-      }
-      break;
-    }
+void CVTypeDumper::visitEnumType(TypeLeafKind Leaf, const EnumType *Enum,
+                                 ArrayRef<uint8_t> LeafData) {
+  W.printNumber("NumEnumerators", Enum->NumEnumerators);
+  W.printFlags("Properties", uint16_t(Enum->Properties),
+               makeArrayRef(ClassOptionNames));
+  printTypeIndex("UnderlyingType", Enum->UnderlyingType);
+  printTypeIndex("FieldListType", Enum->FieldListType);
+  Name = getBytesAsCString(LeafData);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitArrayType(TypeLeafKind Leaf, const ArrayType *AT,
+                                  ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("ElementType", AT->ElementType);
+  printTypeIndex("IndexType", AT->IndexType);
+  uint64_t SizeOf;
+  error(decodeUIntLeaf(LeafData, SizeOf));
+  W.printNumber("SizeOf", SizeOf);
+  Name = getBytesAsCString(LeafData);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitVFTableType(TypeLeafKind Leaf, const VFTableType *VFT,
+                                    ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("CompleteClass", VFT->CompleteClass);
+  printTypeIndex("OverriddenVFTable", VFT->OverriddenVFTable);
+  W.printHex("VFPtrOffset", VFT->VFPtrOffset);
+  StringRef NamesData = getBytesAsCharacters(LeafData.slice(0, VFT->NamesLen));
+  std::tie(Name, NamesData) = NamesData.split('\0');
+  W.printString("VFTableName", Name);
+  while (!NamesData.empty()) {
+    StringRef MethodName;
+    std::tie(MethodName, NamesData) = NamesData.split('\0');
+    W.printString("MethodName", MethodName);
+  }
+}
+
+void CVTypeDumper::visitMemberFuncId(TypeLeafKind Leaf, const MemberFuncId *Id,
+                                     ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("ClassType", Id->ClassType);
+  printTypeIndex("FunctionType", Id->FunctionType);
+  Name = getBytesAsCString(LeafData);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitProcedureType(TypeLeafKind Leaf,
+                                      const ProcedureType *Proc,
+                                      ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("ReturnType", Proc->ReturnType);
+  W.printEnum("CallingConvention", uint8_t(Proc->CallConv),
+              makeArrayRef(CallingConventions));
+  W.printFlags("FunctionOptions", uint8_t(Proc->Options),
+               makeArrayRef(FunctionOptionEnum));
+  W.printNumber("NumParameters", Proc->NumParameters);
+  printTypeIndex("ArgListType", Proc->ArgListType);
+
+  StringRef ReturnTypeName = getTypeName(Proc->ReturnType);
+  StringRef ArgListTypeName = getTypeName(Proc->ArgListType);
+  SmallString<256> TypeName(ReturnTypeName);
+  TypeName.push_back(' ');
+  TypeName.append(ArgListTypeName);
+  Name = TypeNames.insert(TypeName).first->getKey();
+}
+
+void CVTypeDumper::visitMemberFunctionType(TypeLeafKind Leaf,
+                                           const MemberFunctionType *MemberFunc,
+                                           ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("ReturnType", MemberFunc->ReturnType);
+  printTypeIndex("ClassType", MemberFunc->ClassType);
+  printTypeIndex("ThisType", MemberFunc->ThisType);
+  W.printEnum("CallingConvention", uint8_t(MemberFunc->CallConv),
+              makeArrayRef(CallingConventions));
+  W.printFlags("FunctionOptions", uint8_t(MemberFunc->Options),
+               makeArrayRef(FunctionOptionEnum));
+  W.printNumber("NumParameters", MemberFunc->NumParameters);
+  printTypeIndex("ArgListType", MemberFunc->ArgListType);
+  W.printNumber("ThisAdjustment", MemberFunc->ThisAdjustment);
+
+  StringRef ReturnTypeName = getTypeName(MemberFunc->ReturnType);
+  StringRef ClassTypeName = getTypeName(MemberFunc->ClassType);
+  StringRef ArgListTypeName = getTypeName(MemberFunc->ArgListType);
+  SmallString<256> TypeName(ReturnTypeName);
+  TypeName.push_back(' ');
+  TypeName.append(ClassTypeName);
+  TypeName.append("::");
+  TypeName.append(ArgListTypeName);
+  Name = TypeNames.insert(TypeName).first->getKey();
+}
+
+void CVTypeDumper::visitMethodList(TypeLeafKind Leaf,
+                                   ArrayRef<uint8_t> LeafData) {
+  while (!LeafData.empty()) {
+    const MethodListEntry *Method;
+    if (!consumeObject(LeafData, Method))
+      return;
+    ListScope S(W, "Method");
+    printMemberAttributes(Method->Attrs);
+    printTypeIndex("Type", Method->Type);
+    if (Method->isIntroducedVirtual()) {
+      const little32_t *VFTOffsetPtr;
+      if (!consumeObject(LeafData, VFTOffsetPtr))
+        return;
+      W.printHex("VFTableOffset", *VFTOffsetPtr);
     }
-
-    if (opts::CodeViewSubsectionBytes)
-      W.printBinaryBlock("LeafData", LeafData);
-
-    CVUDTNames.push_back(Name);
   }
 }
 
-static StringRef skipPadding(StringRef Data) {
-  if (Data.empty())
-    return Data;
-  uint8_t Leaf = Data.front();
-  if (Leaf < LF_PAD0)
-    return Data;
-  // Leaf is greater than 0xf0. We should advance by the number of bytes in the
-  // low 4 bits.
-  return Data.drop_front(Leaf & 0x0F);
+void CVTypeDumper::visitFuncId(TypeLeafKind Leaf, const FuncId *Func,
+                               ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("ParentScope", Func->ParentScope);
+  printTypeIndex("FunctionType", Func->FunctionType);
+  Name = getBytesAsCString(LeafData);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitTypeServer2(TypeLeafKind Leaf,
+                                    const TypeServer2 *TypeServer,
+                                    ArrayRef<uint8_t> LeafData) {
+  W.printBinary("Signature", StringRef(TypeServer->Signature, 16));
+  W.printNumber("Age", TypeServer->Age);
+  Name = getBytesAsCString(LeafData);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitPointerType(TypeLeafKind Leaf, const PointerType *Ptr,
+                                    ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("PointeeType", Ptr->PointeeType);
+  W.printHex("PointerAttributes", Ptr->Attrs);
+  W.printEnum("PtrType", unsigned(Ptr->getPtrKind()),
+              makeArrayRef(PtrKindNames));
+  W.printEnum("PtrMode", unsigned(Ptr->getPtrMode()),
+              makeArrayRef(PtrModeNames));
+  W.printNumber("IsFlat", Ptr->isFlat());
+  W.printNumber("IsConst", Ptr->isConst());
+  W.printNumber("IsVolatile", Ptr->isVolatile());
+  W.printNumber("IsUnaligned", Ptr->isUnaligned());
+
+  if (Ptr->isPointerToMember()) {
+    const PointerToMemberTail *PMT;
+    if (!consumeObject(LeafData, PMT))
+      return;
+    printTypeIndex("ClassType", PMT->ClassType);
+    W.printEnum("Representation", PMT->Representation,
+                makeArrayRef(PtrMemberRepNames));
+
+    StringRef PointeeName = getTypeName(Ptr->PointeeType);
+    StringRef ClassName = getTypeName(PMT->ClassType);
+    SmallString<256> TypeName(PointeeName);
+    TypeName.push_back(' ');
+    TypeName.append(ClassName);
+    TypeName.append("::*");
+    Name = TypeNames.insert(TypeName).first->getKey();
+  } else {
+    W.printBinaryBlock("TailData", getBytesAsCharacters(LeafData));
+
+    SmallString<256> TypeName;
+    if (Ptr->isConst())
+      TypeName.append("const ");
+    if (Ptr->isVolatile())
+      TypeName.append("volatile ");
+    if (Ptr->isUnaligned())
+      TypeName.append("__unaligned ");
+
+    TypeName.append(getTypeName(Ptr->PointeeType));
+
+    if (Ptr->getPtrMode() == PointerMode::LValueReference)
+      TypeName.append("&");
+    else if (Ptr->getPtrMode() == PointerMode::RValueReference)
+      TypeName.append("&&");
+    else if (Ptr->getPtrMode() == PointerMode::Pointer)
+      TypeName.append("*");
+
+    Name = TypeNames.insert(TypeName).first->getKey();
+  }
+}
+
+void CVTypeDumper::visitTypeModifier(TypeLeafKind Leaf, const TypeModifier *Mod,
+                                     ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("ModifiedType", Mod->ModifiedType);
+  W.printFlags("Modifiers", Mod->Modifiers, makeArrayRef(TypeModifierNames));
+
+  StringRef ModifiedName = getTypeName(Mod->ModifiedType);
+  SmallString<256> TypeName;
+  if (Mod->Modifiers & uint16_t(ModifierOptions::Const))
+    TypeName.append("const ");
+  if (Mod->Modifiers & uint16_t(ModifierOptions::Volatile))
+    TypeName.append("volatile ");
+  if (Mod->Modifiers & uint16_t(ModifierOptions::Unaligned))
+    TypeName.append("__unaligned ");
+  TypeName.append(ModifiedName);
+  Name = TypeNames.insert(TypeName).first->getKey();
+}
+
+void CVTypeDumper::visitVTableShape(TypeLeafKind Leaf, const VTableShape *Shape,
+                                    ArrayRef<uint8_t> LeafData) {
+  unsigned VFEntryCount = Shape->VFEntryCount;
+  W.printNumber("VFEntryCount", VFEntryCount);
+  // We could print out whether the methods are near or far, but in practice
+  // today everything is CV_VTS_near32, so it's just noise.
+}
+
+void CVTypeDumper::visitUDTSrcLine(TypeLeafKind Leaf, const UDTSrcLine *Line,
+                                   ArrayRef<uint8_t> LeafData) {
+  printTypeIndex("UDT", Line->UDT);
+  printTypeIndex("SourceFile", Line->SourceFile);
+  W.printNumber("LineNumber", Line->LineNumber);
+}
+
+void CVTypeDumper::visitBuildInfo(TypeLeafKind Leaf, const BuildInfo *Args,
+                                  ArrayRef<uint8_t> LeafData) {
+  W.printNumber("NumArgs", Args->NumArgs);
+
+  ListScope Arguments(W, "Arguments");
+  for (uint32_t ArgI = 0; ArgI != Args->NumArgs; ++ArgI) {
+    const TypeIndex *Type;
+    if (!consumeObject(LeafData, Type))
+      return;
+    printTypeIndex("ArgType", *Type);
+  }
 }
 
 void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) {
@@ -2348,140 +2339,112 @@ void CVTypeDumper::printMemberAttributes
   }
 }
 
-void CVTypeDumper::printCodeViewFieldList(StringRef FieldData) {
-  while (!FieldData.empty()) {
-    const ulittle16_t *LeafPtr;
-    error(consumeObject(FieldData, LeafPtr));
-    uint16_t Leaf = *LeafPtr;
-    switch (Leaf) {
-    default:
-      W.printHex("UnknownMember", Leaf);
-      // We can't advance once we hit an unknown field. The size is not encoded.
-      return;
-
-    case LF_NESTTYPE: {
-      const NestedType *Nested;
-      error(consumeObject(FieldData, Nested));
-      DictScope S(W, "NestedType");
-      printTypeIndex("Type", Nested->Type);
-      StringRef Name;
-      std::tie(Name, FieldData) = FieldData.split('\0');
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_ONEMETHOD: {
-      const OneMethod *Method;
-      error(consumeObject(FieldData, Method));
-      DictScope S(W, "OneMethod");
-      printMemberAttributes(Method->Attrs);
-      printTypeIndex("Type", Method->Type);
-      // If virtual, then read the vftable offset.
-      if (Method->isIntroducedVirtual()) {
-        const little32_t *VFTOffsetPtr;
-        error(consumeObject(FieldData, VFTOffsetPtr));
-        W.printHex("VFTableOffset", *VFTOffsetPtr);
-      }
-      StringRef Name;
-      std::tie(Name, FieldData) = FieldData.split('\0');
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_METHOD: {
-      const OverloadedMethod *Method;
-      error(consumeObject(FieldData, Method));
-      DictScope S(W, "OverloadedMethod");
-      W.printHex("MethodCount", Method->MethodCount);
-      W.printHex("MethodListIndex", Method->MethList.getIndex());
-      StringRef Name;
-      std::tie(Name, FieldData) = FieldData.split('\0');
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_MEMBER: {
-      const DataMember *Field;
-      error(consumeObject(FieldData, Field));
-      DictScope S(W, "DataMember");
-      printMemberAttributes(Field->Attrs);
-      printTypeIndex("Type", Field->Type);
-      uint64_t FieldOffset;
-      error(decodeUIntLeaf(FieldData, FieldOffset));
-      W.printHex("FieldOffset", FieldOffset);
-      StringRef Name;
-      std::tie(Name, FieldData) = FieldData.split('\0');
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_STMEMBER: {
-      const StaticDataMember *Field;
-      error(consumeObject(FieldData, Field));
-      DictScope S(W, "StaticDataMember");
-      printMemberAttributes(Field->Attrs);
-      printTypeIndex("Type", Field->Type);
-      StringRef Name;
-      std::tie(Name, FieldData) = FieldData.split('\0');
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_VFUNCTAB: {
-      const VirtualFunctionPointer *VFTable;
-      error(consumeObject(FieldData, VFTable));
-      DictScope S(W, "VirtualFunctionPointer");
-      printTypeIndex("Type", VFTable->Type);
-      break;
-    }
-
-    case LF_ENUMERATE: {
-      const Enumerator *Enum;
-      error(consumeObject(FieldData, Enum));
-      DictScope S(W, "Enumerator");
-      printMemberAttributes(Enum->Attrs);
-      APSInt EnumValue;
-      error(decodeNumerictLeaf(FieldData, EnumValue));
-      W.printNumber("EnumValue", EnumValue);
-      StringRef Name;
-      std::tie(Name, FieldData) = FieldData.split('\0');
-      W.printString("Name", Name);
-      break;
-    }
-
-    case LF_BCLASS:
-    case LF_BINTERFACE: {
-      const BaseClass *Base;
-      error(consumeObject(FieldData, Base));
-      DictScope S(W, "BaseClass");
-      printMemberAttributes(Base->Attrs);
-      printTypeIndex("BaseType", Base->BaseType);
-      uint64_t BaseOffset;
-      error(decodeUIntLeaf(FieldData, BaseOffset));
-      W.printHex("BaseOffset", BaseOffset);
-      break;
-    }
-
-    case LF_VBCLASS:
-    case LF_IVBCLASS: {
-      const VirtualBaseClass *Base;
-      error(consumeObject(FieldData, Base));
-      DictScope S(W, "VirtualBaseClass");
-      printMemberAttributes(Base->Attrs);
-      printTypeIndex("BaseType",  Base->BaseType);
-      printTypeIndex("VBPtrType", Base->VBPtrType);
-      uint64_t VBPtrOffset, VBTableIndex;
-      error(decodeUIntLeaf(FieldData, VBPtrOffset));
-      error(decodeUIntLeaf(FieldData, VBTableIndex));
-      W.printHex("VBPtrOffset", VBPtrOffset);
-      W.printHex("VBTableIndex", VBTableIndex);
-      break;
-    }
-    }
+void CVTypeDumper::visitUnknownMember(TypeLeafKind Leaf) {
+  W.printHex("UnknownMember", unsigned(Leaf));
+}
 
-    // Handle padding.
-    FieldData = skipPadding(FieldData);
+void CVTypeDumper::visitNestedType(TypeLeafKind Leaf, const NestedType *Nested,
+                                   ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "NestedType");
+  printTypeIndex("Type", Nested->Type);
+  StringRef Name = getBytesAsCString(FieldData);
+  FieldData = FieldData.drop_front(Name.size() + 1);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitOneMethod(TypeLeafKind Leaf, const OneMethod *Method,
+                                  ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "OneMethod");
+  printMemberAttributes(Method->Attrs);
+  printTypeIndex("Type", Method->Type);
+  // If virtual, then read the vftable offset.
+  if (Method->isIntroducedVirtual()) {
+    const little32_t *VFTOffsetPtr;
+    if (!consumeObject(FieldData, VFTOffsetPtr))
+      return;
+    W.printHex("VFTableOffset", *VFTOffsetPtr);
   }
+  StringRef Name = getBytesAsCString(FieldData);
+  FieldData = FieldData.drop_front(Name.size() + 1);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitOverloadedMethod(TypeLeafKind Leaf,
+                                         const OverloadedMethod *Method,
+                                         ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "OverloadedMethod");
+  W.printHex("MethodCount", Method->MethodCount);
+  W.printHex("MethodListIndex", Method->MethList.getIndex());
+  StringRef Name = getBytesAsCString(FieldData);
+  FieldData = FieldData.drop_front(Name.size() + 1);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitDataMember(TypeLeafKind Leaf, const DataMember *Field,
+                                   ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "DataMember");
+  printMemberAttributes(Field->Attrs);
+  printTypeIndex("Type", Field->Type);
+  uint64_t FieldOffset;
+  error(decodeUIntLeaf(FieldData, FieldOffset));
+  W.printHex("FieldOffset", FieldOffset);
+  StringRef Name = getBytesAsCString(FieldData);
+  FieldData = FieldData.drop_front(Name.size() + 1);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitStaticDataMember(TypeLeafKind Leaf,
+                                         const StaticDataMember *Field,
+                                         ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "StaticDataMember");
+  printMemberAttributes(Field->Attrs);
+  printTypeIndex("Type", Field->Type);
+  StringRef Name = getBytesAsCString(FieldData);
+  FieldData = FieldData.drop_front(Name.size() + 1);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitVirtualFunctionPointer(
+    TypeLeafKind Leaf, const VirtualFunctionPointer *VFTable,
+    ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "VirtualFunctionPointer");
+  printTypeIndex("Type", VFTable->Type);
+}
+
+void CVTypeDumper::visitEnumerator(TypeLeafKind Leaf, const Enumerator *Enum,
+                                   ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "Enumerator");
+  printMemberAttributes(Enum->Attrs);
+  APSInt EnumValue;
+  error(decodeNumerictLeaf(FieldData, EnumValue));
+  W.printNumber("EnumValue", EnumValue);
+  StringRef Name = getBytesAsCString(FieldData);
+  FieldData = FieldData.drop_front(Name.size() + 1);
+  W.printString("Name", Name);
+}
+
+void CVTypeDumper::visitBaseClass(TypeLeafKind Leaf, const BaseClass *Base,
+                                  ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "BaseClass");
+  printMemberAttributes(Base->Attrs);
+  printTypeIndex("BaseType", Base->BaseType);
+  uint64_t BaseOffset;
+  error(decodeUIntLeaf(FieldData, BaseOffset));
+  W.printHex("BaseOffset", BaseOffset);
+}
+
+void CVTypeDumper::visitVirtualBaseClass(TypeLeafKind Leaf,
+                                         const VirtualBaseClass *Base,
+                                         ArrayRef<uint8_t> &FieldData) {
+  DictScope S(W, "VirtualBaseClass");
+  printMemberAttributes(Base->Attrs);
+  printTypeIndex("BaseType", Base->BaseType);
+  printTypeIndex("VBPtrType", Base->VBPtrType);
+  uint64_t VBPtrOffset, VBTableIndex;
+  error(decodeUIntLeaf(FieldData, VBPtrOffset));
+  error(decodeUIntLeaf(FieldData, VBTableIndex));
+  W.printHex("VBPtrOffset", VBPtrOffset);
+  W.printHex("VBTableIndex", VBTableIndex);
 }
 
 void COFFDumper::printSections() {




More information about the llvm-commits mailing list