[llvm] r272929 - Resubmit "[pdb] Change type visitor pattern to be dynamic."

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 16 11:22:27 PDT 2016


Author: zturner
Date: Thu Jun 16 13:22:27 2016
New Revision: 272929

URL: http://llvm.org/viewvc/llvm-project?rev=272929&view=rev
Log:
Resubmit "[pdb] Change type visitor pattern to be dynamic."

There was a regression introduced during type stream merging when
visiting a field list record.  This has been fixed in this patch.

Added:
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h
    llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
Modified:
    llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDumper.h
    llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def
    llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawError.h
    llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
    llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt
    llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp
    llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
    llvm/trunk/lib/DebugInfo/PDB/Raw/RawError.cpp
    llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp
    llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp
    llvm/trunk/tools/llvm-readobj/COFFDumper.cpp

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h Thu Jun 16 13:22:27 2016
@@ -11,151 +11,31 @@
 #define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
 
 #include "llvm/DebugInfo/CodeView/CVRecord.h"
-#include "llvm/DebugInfo/CodeView/CodeView.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/Support/ErrorOr.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/Error.h"
 
 namespace llvm {
 namespace codeview {
 
-template <typename Derived>
 class CVTypeVisitor {
 public:
-  CVTypeVisitor() {}
+  explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
 
-  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(EnumName, EnumVal, Name)                                   \
-  void visit##Name(Name##Record &Record) {}
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  void visit##Name(Name##Record &Record) {}
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "TypeRecords.def"
-
-  void visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
-    ArrayRef<uint8_t> LeafData = Record.Data;
-    auto *DerivedThis = static_cast<Derived *>(this);
-    DerivedThis->visitTypeBegin(Record);
-    switch (Record.Type) {
-    default:
-      DerivedThis->visitUnknownType(Record);
-      break;
-    case LF_FIELDLIST:
-      DerivedThis->visitFieldList(Record.Type, LeafData);
-      break;
-#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
-  case EnumName: {                                                             \
-    TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName);                 \
-    auto Result = Name##Record::deserialize(RK, LeafData);                     \
-    if (Result.getError())                                                     \
-      return parseError();                                                     \
-    DerivedThis->visit##Name(*Result);                                         \
-    break;                                                                     \
-  }
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)                  \
-  TYPE_RECORD(EnumVal, EnumVal, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name)
-#include "TypeRecords.def"
-      }
-      DerivedThis->visitTypeEnd(Record);
-  }
+  Error visitTypeRecord(const CVRecord<TypeLeafKind> &Record);
 
   /// Visits the type records in Data. Sets the error flag on parse failures.
-  void visitTypeStream(const CVTypeArray &Types) {
-    for (const auto &I : Types) {
-      visitTypeRecord(I);
-      if (hadError())
-        break;
-    }
-  }
-
-  /// Action to take on unknown types. By default, they are ignored.
-  void visitUnknownType(const CVRecord<TypeLeafKind> &Record) {}
-
-  /// Paired begin/end actions for all types. Receives all record data,
-  /// including the fixed-length record prefix.
-  void visitTypeBegin(const CVRecord<TypeLeafKind> &Record) {}
-  void visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {}
-
-  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.
-    unsigned BytesToAdvance = Leaf & 0x0F;
-    if (Data.size() < BytesToAdvance) {
-      parseError();
-      return None;
-    }
-    return Data.drop_front(BytesToAdvance);
-  }
+  Error visitTypeStream(const CVTypeArray &Types);
+
+  Error skipPadding(ArrayRef<uint8_t> &Data);
 
   /// 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) {
-    auto *DerivedThis = static_cast<Derived *>(this);
-    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.
-        DerivedThis->visitUnknownMember(Leaf);
-        return parseError();
-#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  case EnumName: {                                                             \
-    TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName);                 \
-    auto Result = Name##Record::deserialize(RK, FieldData);                    \
-    if (Result.getError())                                                     \
-      return parseError();                                                     \
-    DerivedThis->visit##Name(*Result);                                         \
-    break;                                                                     \
-  }
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)                \
-  MEMBER_RECORD(EnumVal, EnumVal, AliasName)
-#include "TypeRecords.def"
-      }
-      FieldData = skipPadding(FieldData);
-      if (hadError())
-        break;
-    }
-  }
-
-  /// 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) {}
-
-  /// Helper for returning from a void function when the stream is corrupted.
-  void parseError() { HadError = true; }
+  Error visitFieldList(const CVRecord<TypeLeafKind> &Record);
 
 private:
-  /// Whether a type stream parsing error was encountered.
-  bool HadError = false;
+  /// The interface to the class that gets notified of each visitation.
+  TypeVisitorCallbacks &Callbacks;
 };
 
 } // end namespace codeview

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDumper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDumper.h?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDumper.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDumper.h Thu Jun 16 13:22:27 2016
@@ -14,6 +14,7 @@
 #include "llvm/ADT/StringSet.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
 
 namespace llvm {
 class ScopedPrinter;
@@ -21,7 +22,7 @@ class ScopedPrinter;
 namespace codeview {
 
 /// Dumper for CodeView type streams found in COFF object files and PDB files.
-class CVTypeDumper {
+class CVTypeDumper : public TypeVisitorCallbacks {
 public:
   CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes)
       : W(W), PrintRecordBytes(PrintRecordBytes) {}
@@ -33,17 +34,17 @@ public:
   /// 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 CVRecord<TypeLeafKind> &Record);
+  Error dump(const CVRecord<TypeLeafKind> &Record);
 
   /// Dumps the type records in Types. Returns false if there was a type stream
   /// parse error, and true otherwise.
-  bool dump(const CVTypeArray &Types);
+  Error dump(const CVTypeArray &Types);
 
   /// Dumps the type records in Data. Returns false if there was a type stream
   /// parse error, and true otherwise. Use this method instead of the
   /// CVTypeArray overload when type records are laid out contiguously in
   /// memory.
-  bool dump(ArrayRef<uint8_t> Data);
+  Error dump(ArrayRef<uint8_t> Data);
 
   /// Gets the type index for the next type record.
   unsigned getNextTypeIndex() const {
@@ -61,11 +62,35 @@ public:
   void setPrinter(ScopedPrinter *P);
   ScopedPrinter *getPrinter() { return W; }
 
+  /// Action to take on unknown types. By default, they are ignored.
+  Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override;
+  Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) override;
+
+  /// Paired begin/end actions for all types. Receives all record data,
+  /// including the fixed-length record prefix.
+  Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
+  Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
+  Error visit##Name(Name##Record &Record) override;
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "TypeRecords.def"
+
 private:
+  void printMemberAttributes(MemberAttributes Attrs);
+  void printMemberAttributes(MemberAccess Access, MethodKind Kind,
+                             MethodOptions Options);
+
   ScopedPrinter *W;
 
   bool PrintRecordBytes = false;
 
+  /// 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.

Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def Thu Jun 16 13:22:27 2016
@@ -83,6 +83,7 @@ TYPE_RECORD(LF_STRING_ID, 0x1605, String
 TYPE_RECORD(LF_UDT_SRC_LINE, 0x1606, UdtSourceLine)
 TYPE_RECORD(LF_UDT_MOD_SRC_LINE, 0x1607, UdtModSourceLine)
 
+
 TYPE_RECORD(LF_METHODLIST, 0x1206, MethodOverloadList)
 
 
@@ -195,6 +196,8 @@ CV_TYPE(LF_MODIFIER_EX, 0x1518)
 CV_TYPE(LF_VECTOR, 0x151b)
 CV_TYPE(LF_MATRIX, 0x151c)
 
+// ID leaf records. Subsequent leaf types may be referenced from .debug$S.
+
 // Numeric leaf types. These are generally contained in other records, and not
 // encountered in the main type stream.
 

Added: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h?rev=272929&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h Thu Jun 16 13:22:27 2016
@@ -0,0 +1,61 @@
+//===- TypeVisitorCallbacks.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_TYPEVISITORCALLBACKS_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPEVISITORCALLBACKS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace codeview {
+class TypeVisitorCallbacks {
+  friend class CVTypeVisitor;
+
+public:
+  virtual ~TypeVisitorCallbacks() {}
+
+  /// Action to take on unknown types. By default, they are ignored.
+  virtual Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) {
+    return Error::success();
+  }
+  virtual Error visitUnknownMember(const CVRecord<TypeLeafKind> &Record) {
+    return Error::success();
+  }
+
+  /// Paired begin/end actions for all types. Receives all record data,
+  /// including the fixed-length record prefix.
+  virtual Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) {
+    return Error::success();
+  }
+  virtual Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
+    return Error::success();
+  }
+
+  virtual Error visitFieldListBegin(const CVRecord<TypeLeafKind> &Record) {
+    return Error::success();
+  }
+
+  virtual Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) {
+    return Error::success();
+  }
+
+#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
+  virtual Error visit##Name(Name##Record &Record) { return Error::success(); }
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "TypeRecords.def"
+};
+}
+}
+
+#endif
\ No newline at end of file

Modified: llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawError.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawError.h?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawError.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/PDB/Raw/RawError.h Thu Jun 16 13:22:27 2016
@@ -25,6 +25,7 @@ enum class raw_error_code {
   index_out_of_bounds,
   invalid_block_address,
   not_writable,
+  invalid_tpi_hash,
 };
 
 /// Base class for errors originating when parsing raw PDB files

Modified: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Thu Jun 16 13:22:27 2016
@@ -322,10 +322,9 @@ void CodeViewDebug::emitTypeInformation(
           ScopedPrinter SP(CommentOS);
           SP.setPrefix(CommentPrefix);
           CVTD.setPrinter(&SP);
-          bool DumpSuccess =
-              CVTD.dump({Record.bytes_begin(), Record.bytes_end()});
-          (void)DumpSuccess;
-          assert(DumpSuccess && "produced malformed type record");
+          Error EC = CVTD.dump({Record.bytes_begin(), Record.bytes_end()});
+          assert(!EC && "produced malformed type record");
+          consumeError(std::move(EC));
           // emitRawComment will insert its own tab and comment string before
           // the first line, so strip off our first one. It also prints its own
           // newline.

Modified: llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt Thu Jun 16 13:22:27 2016
@@ -1,6 +1,7 @@
 add_llvm_library(LLVMDebugInfoCodeView
   ByteStream.cpp
   CodeViewError.cpp
+  CVTypeVisitor.cpp
   EnumTables.cpp
   FieldListRecordBuilder.cpp
   Line.cpp

Added: llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp?rev=272929&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp (added)
+++ llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp Thu Jun 16 13:22:27 2016
@@ -0,0 +1,123 @@
+//===- CVTypeVisitor.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+template <typename T>
+static Error takeObject(ArrayRef<uint8_t> &Data, const T *&Res) {
+  if (Data.size() < sizeof(*Res))
+    return llvm::make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+  Res = reinterpret_cast<const T *>(Data.data());
+  Data = Data.drop_front(sizeof(*Res));
+  return Error::success();
+}
+
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
+    : Callbacks(Callbacks) {}
+
+Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) {
+  ArrayRef<uint8_t> LeafData = Record.Data;
+  if (auto EC = Callbacks.visitTypeBegin(Record))
+    return EC;
+  switch (Record.Type) {
+  default:
+    if (auto EC = Callbacks.visitUnknownType(Record))
+      return EC;
+    break;
+  case LF_FIELDLIST:
+    if (auto EC = Callbacks.visitFieldListBegin(Record))
+      return EC;
+    if (auto EC = visitFieldList(Record))
+      return EC;
+    if (auto EC = Callbacks.visitFieldListEnd(Record))
+      return EC;
+    break;
+#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
+  case EnumName: {                                                             \
+    TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName);                 \
+    auto Result = Name##Record::deserialize(RK, LeafData);                     \
+    if (Result.getError())                                                     \
+      return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);   \
+    if (auto EC = Callbacks.visit##Name(*Result))                              \
+      return EC;                                                               \
+    break;                                                                     \
+  }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)                  \
+  TYPE_RECORD(EnumVal, EnumVal, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+  }
+  if (auto EC = Callbacks.visitTypeEnd(Record))
+    return EC;
+  return Error::success();
+}
+
+/// Visits the type records in Data. Sets the error flag on parse failures.
+Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
+  for (const auto &I : Types) {
+    if (auto EC = visitTypeRecord(I))
+      return EC;
+  }
+  return Error::success();
+}
+
+Error CVTypeVisitor::skipPadding(ArrayRef<uint8_t> &Data) {
+  if (Data.empty())
+    return Error::success();
+  uint8_t Leaf = Data.front();
+  if (Leaf < LF_PAD0)
+    return Error::success();
+  // Leaf is greater than 0xf0. We should advance by the number of bytes in
+  // the low 4 bits.
+  unsigned BytesToAdvance = Leaf & 0x0F;
+  if (Data.size() < BytesToAdvance) {
+    return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record,
+                                           "Invalid padding bytes!");
+  }
+  Data = Data.drop_front(BytesToAdvance);
+  return Error::success();
+}
+
+/// Visits individual member records of a field list record. Member records do
+/// not describe their own length, and need special handling.
+Error CVTypeVisitor::visitFieldList(const CVRecord<TypeLeafKind> &Record) {
+  ArrayRef<uint8_t> RecordData = Record.Data;
+  while (!RecordData.empty()) {
+    const ulittle16_t *LeafPtr;
+    if (auto EC = takeObject(RecordData, LeafPtr))
+      return EC;
+    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.
+      if (auto EC = Callbacks.visitUnknownMember(Record))
+        return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  case EnumName: {                                                             \
+    TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName);                 \
+    auto Result = Name##Record::deserialize(RK, RecordData);                   \
+    if (Result.getError())                                                     \
+      return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);   \
+    if (auto EC = Callbacks.visit##Name(*Result))                              \
+      return EC;                                                               \
+    break;                                                                     \
+  }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)                \
+  MEMBER_RECORD(EnumVal, EnumVal, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+    }
+    if (auto EC = skipPadding(RecordData))
+      return EC;
+  }
+  return Error::success();
+}

Modified: llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp Thu Jun 16 13:22:27 2016
@@ -189,55 +189,6 @@ static const EnumEntry<uint8_t> Function
 
 #undef ENUM_ENTRY
 
-
-namespace {
-
-/// Use this private dumper implementation to keep implementation details about
-/// the visitor out of TypeDumper.h.
-class CVTypeDumperImpl : public CVTypeVisitor<CVTypeDumperImpl> {
-public:
-  CVTypeDumperImpl(CVTypeDumper &CVTD, ScopedPrinter &W, bool PrintRecordBytes)
-      : CVTD(CVTD), W(W), PrintRecordBytes(PrintRecordBytes) {}
-
-  /// CVTypeVisitor overrides.
-#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
-  void visit##Name(Name##Record &Record);
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  void visit##Name(Name##Record &Record);
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-
-  void visitUnknownMember(TypeLeafKind Leaf);
-  void visitUnknownType(const CVRecord<TypeLeafKind> &Record);
-
-  void visitTypeBegin(const CVRecord<TypeLeafKind> &Record);
-  void visitTypeEnd(const CVRecord<TypeLeafKind> &Record);
-
-  void printMemberAttributes(MemberAttributes Attrs);
-  void printMemberAttributes(MemberAccess Access, MethodKind Kind,
-                             MethodOptions Options);
-
-private:
-  /// Forwards to the dumper, which holds the persistent state from visitation.
-  StringRef getTypeName(TypeIndex TI) {
-    return CVTD.getTypeName(TI);
-  }
-
-  void printTypeIndex(StringRef FieldName, TypeIndex TI) {
-    CVTD.printTypeIndex(FieldName, TI);
-  }
-
-  CVTypeDumper &CVTD;
-  ScopedPrinter &W;
-  bool PrintRecordBytes = false;
-
-  /// Name of the current type. Only valid before visitTypeEnd.
-  StringRef Name;
-};
-
-} // end anonymous namespace
-
 static StringRef getLeafTypeName(TypeLeafKind LT) {
   switch (LT) {
 #define TYPE_RECORD(ename, value, name)                                        \
@@ -250,39 +201,44 @@ static StringRef getLeafTypeName(TypeLea
   return "UnknownLeaf";
 }
 
-void CVTypeDumperImpl::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) {
+Error CVTypeDumper::visitTypeBegin(const CVRecord<TypeLeafKind> &Record) {
   // Reset Name to the empty string. If the visitor sets it, we know it.
   Name = "";
 
-  W.startLine() << getLeafTypeName(Rec.Type) << " ("
-                << HexNumber(CVTD.getNextTypeIndex()) << ") {\n";
-  W.indent();
-  W.printEnum("TypeLeafKind", unsigned(Rec.Type), makeArrayRef(LeafTypeNames));
+  W->startLine() << getLeafTypeName(Record.Type) << " ("
+                 << HexNumber(getNextTypeIndex()) << ") {\n";
+  W->indent();
+  W->printEnum("TypeLeafKind", unsigned(Record.Type),
+               makeArrayRef(LeafTypeNames));
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitTypeEnd(const CVRecord<TypeLeafKind> &Rec) {
+Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
   // Always record some name for every type, even if Name is empty. CVUDTNames
   // is indexed by type index, and must have one entry for every type.
-  CVTD.recordType(Name);
+  recordType(Name);
+
   if (PrintRecordBytes)
-    W.printBinaryBlock("LeafData", getBytesAsCharacters(Rec.Data));
+    W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
 
-  W.unindent();
-  W.startLine() << "}\n";
+  W->unindent();
+  W->startLine() << "}\n";
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitStringId(StringIdRecord &String) {
+Error CVTypeDumper::visitStringId(StringIdRecord &String) {
   printTypeIndex("Id", String.getId());
-  W.printString("StringData", String.getString());
+  W->printString("StringData", String.getString());
   // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
   Name = String.getString();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitArgList(ArgListRecord &Args) {
+Error CVTypeDumper::visitArgList(ArgListRecord &Args) {
   auto Indices = Args.getIndices();
   uint32_t Size = Indices.size();
-  W.printNumber("NumArgs", Size);
-  ListScope Arguments(W, "Arguments");
+  W->printNumber("NumArgs", Size);
+  ListScope Arguments(*W, "Arguments");
   SmallString<256> TypeName("(");
   for (uint32_t I = 0; I < Size; ++I) {
     printTypeIndex("ArgType", Indices[I]);
@@ -292,77 +248,84 @@ void CVTypeDumperImpl::visitArgList(ArgL
       TypeName.append(", ");
   }
   TypeName.push_back(')');
-  Name = CVTD.saveName(TypeName);
+  Name = saveName(TypeName);
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitClass(ClassRecord &Class) {
+Error CVTypeDumper::visitClass(ClassRecord &Class) {
   uint16_t Props = static_cast<uint16_t>(Class.getOptions());
-  W.printNumber("MemberCount", Class.getMemberCount());
-  W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+  W->printNumber("MemberCount", Class.getMemberCount());
+  W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
   printTypeIndex("FieldList", Class.getFieldList());
   printTypeIndex("DerivedFrom", Class.getDerivationList());
   printTypeIndex("VShape", Class.getVTableShape());
-  W.printNumber("SizeOf", Class.getSize());
-  W.printString("Name", Class.getName());
+  W->printNumber("SizeOf", Class.getSize());
+  W->printString("Name", Class.getName());
   if (Props & uint16_t(ClassOptions::HasUniqueName))
-    W.printString("LinkageName", Class.getUniqueName());
+    W->printString("LinkageName", Class.getUniqueName());
   Name = Class.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitUnion(UnionRecord &Union) {
+Error CVTypeDumper::visitUnion(UnionRecord &Union) {
   uint16_t Props = static_cast<uint16_t>(Union.getOptions());
-  W.printNumber("MemberCount", Union.getMemberCount());
-  W.printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+  W->printNumber("MemberCount", Union.getMemberCount());
+  W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
   printTypeIndex("FieldList", Union.getFieldList());
-  W.printNumber("SizeOf", Union.getSize());
-  W.printString("Name", Union.getName());
+  W->printNumber("SizeOf", Union.getSize());
+  W->printString("Name", Union.getName());
   if (Props & uint16_t(ClassOptions::HasUniqueName))
-    W.printString("LinkageName", Union.getUniqueName());
+    W->printString("LinkageName", Union.getUniqueName());
   Name = Union.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitEnum(EnumRecord &Enum) {
-  W.printNumber("NumEnumerators", Enum.getMemberCount());
-  W.printFlags("Properties", uint16_t(Enum.getOptions()),
-               makeArrayRef(ClassOptionNames));
+Error CVTypeDumper::visitEnum(EnumRecord &Enum) {
+  W->printNumber("NumEnumerators", Enum.getMemberCount());
+  W->printFlags("Properties", uint16_t(Enum.getOptions()),
+                makeArrayRef(ClassOptionNames));
   printTypeIndex("UnderlyingType", Enum.getUnderlyingType());
   printTypeIndex("FieldListType", Enum.getFieldList());
-  W.printString("Name", Enum.getName());
+  W->printString("Name", Enum.getName());
   Name = Enum.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitArray(ArrayRecord &AT) {
+Error CVTypeDumper::visitArray(ArrayRecord &AT) {
   printTypeIndex("ElementType", AT.getElementType());
   printTypeIndex("IndexType", AT.getIndexType());
-  W.printNumber("SizeOf", AT.getSize());
-  W.printString("Name", AT.getName());
+  W->printNumber("SizeOf", AT.getSize());
+  W->printString("Name", AT.getName());
   Name = AT.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitVFTable(VFTableRecord &VFT) {
+Error CVTypeDumper::visitVFTable(VFTableRecord &VFT) {
   printTypeIndex("CompleteClass", VFT.getCompleteClass());
   printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
-  W.printHex("VFPtrOffset", VFT.getVFPtrOffset());
-  W.printString("VFTableName", VFT.getName());
+  W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
+  W->printString("VFTableName", VFT.getName());
   for (auto N : VFT.getMethodNames())
-    W.printString("MethodName", N);
+    W->printString("MethodName", N);
   Name = VFT.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitMemberFuncId(MemberFuncIdRecord &Id) {
+Error CVTypeDumper::visitMemberFuncId(MemberFuncIdRecord &Id) {
   printTypeIndex("ClassType", Id.getClassType());
   printTypeIndex("FunctionType", Id.getFunctionType());
-  W.printString("Name", Id.getName());
+  W->printString("Name", Id.getName());
   Name = Id.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitProcedure(ProcedureRecord &Proc) {
+Error CVTypeDumper::visitProcedure(ProcedureRecord &Proc) {
   printTypeIndex("ReturnType", Proc.getReturnType());
-  W.printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
-              makeArrayRef(CallingConventions));
-  W.printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
-               makeArrayRef(FunctionOptionEnum));
-  W.printNumber("NumParameters", Proc.getParameterCount());
+  W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
+               makeArrayRef(CallingConventions));
+  W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
+                makeArrayRef(FunctionOptionEnum));
+  W->printNumber("NumParameters", Proc.getParameterCount());
   printTypeIndex("ArgListType", Proc.getArgumentList());
 
   StringRef ReturnTypeName = getTypeName(Proc.getReturnType());
@@ -370,20 +333,21 @@ void CVTypeDumperImpl::visitProcedure(Pr
   SmallString<256> TypeName(ReturnTypeName);
   TypeName.push_back(' ');
   TypeName.append(ArgListTypeName);
-  Name = CVTD.saveName(TypeName);
+  Name = saveName(TypeName);
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitMemberFunction(MemberFunctionRecord &MF) {
+Error CVTypeDumper::visitMemberFunction(MemberFunctionRecord &MF) {
   printTypeIndex("ReturnType", MF.getReturnType());
   printTypeIndex("ClassType", MF.getClassType());
   printTypeIndex("ThisType", MF.getThisType());
-  W.printEnum("CallingConvention", uint8_t(MF.getCallConv()),
-              makeArrayRef(CallingConventions));
-  W.printFlags("FunctionOptions", uint8_t(MF.getOptions()),
-               makeArrayRef(FunctionOptionEnum));
-  W.printNumber("NumParameters", MF.getParameterCount());
+  W->printEnum("CallingConvention", uint8_t(MF.getCallConv()),
+               makeArrayRef(CallingConventions));
+  W->printFlags("FunctionOptions", uint8_t(MF.getOptions()),
+                makeArrayRef(FunctionOptionEnum));
+  W->printNumber("NumParameters", MF.getParameterCount());
   printTypeIndex("ArgListType", MF.getArgumentList());
-  W.printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
+  W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
 
   StringRef ReturnTypeName = getTypeName(MF.getReturnType());
   StringRef ClassTypeName = getTypeName(MF.getClassType());
@@ -393,52 +357,56 @@ void CVTypeDumperImpl::visitMemberFuncti
   TypeName.append(ClassTypeName);
   TypeName.append("::");
   TypeName.append(ArgListTypeName);
-  Name = CVTD.saveName(TypeName);
+  Name = saveName(TypeName);
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitMethodOverloadList(
+Error CVTypeDumper::visitMethodOverloadList(
     MethodOverloadListRecord &MethodList) {
   for (auto &M : MethodList.getMethods()) {
-    ListScope S(W, "Method");
+    ListScope S(*W, "Method");
     printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions());
     printTypeIndex("Type", M.getType());
     if (M.isIntroducingVirtual())
-      W.printHex("VFTableOffset", M.getVFTableOffset());
+      W->printHex("VFTableOffset", M.getVFTableOffset());
   }
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitFuncId(FuncIdRecord &Func) {
+Error CVTypeDumper::visitFuncId(FuncIdRecord &Func) {
   printTypeIndex("ParentScope", Func.getParentScope());
   printTypeIndex("FunctionType", Func.getFunctionType());
-  W.printString("Name", Func.getName());
+  W->printString("Name", Func.getName());
   Name = Func.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitTypeServer2(TypeServer2Record &TS) {
-  W.printBinary("Signature", TS.getGuid());
-  W.printNumber("Age", TS.getAge());
-  W.printString("Name", TS.getName());
+Error CVTypeDumper::visitTypeServer2(TypeServer2Record &TS) {
+  W->printBinary("Signature", TS.getGuid());
+  W->printNumber("Age", TS.getAge());
+  W->printString("Name", TS.getName());
   Name = TS.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitPointer(PointerRecord &Ptr) {
+Error CVTypeDumper::visitPointer(PointerRecord &Ptr) {
   printTypeIndex("PointeeType", Ptr.getReferentType());
-  W.printHex("PointerAttributes", uint32_t(Ptr.getOptions()));
-  W.printEnum("PtrType", unsigned(Ptr.getPointerKind()),
-              makeArrayRef(PtrKindNames));
-  W.printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames));
-
-  W.printNumber("IsFlat", Ptr.isFlat());
-  W.printNumber("IsConst", Ptr.isConst());
-  W.printNumber("IsVolatile", Ptr.isVolatile());
-  W.printNumber("IsUnaligned", Ptr.isUnaligned());
+  W->printHex("PointerAttributes", uint32_t(Ptr.getOptions()));
+  W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
+               makeArrayRef(PtrKindNames));
+  W->printEnum("PtrMode", unsigned(Ptr.getMode()), 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 MemberPointerInfo &MI = Ptr.getMemberInfo();
 
     printTypeIndex("ClassType", MI.getContainingType());
-    W.printEnum("Representation", uint16_t(MI.getRepresentation()),
-                makeArrayRef(PtrMemberRepNames));
+    W->printEnum("Representation", uint16_t(MI.getRepresentation()),
+                 makeArrayRef(PtrMemberRepNames));
 
     StringRef PointeeName = getTypeName(Ptr.getReferentType());
     StringRef ClassName = getTypeName(MI.getContainingType());
@@ -446,7 +414,7 @@ void CVTypeDumperImpl::visitPointer(Poin
     TypeName.push_back(' ');
     TypeName.append(ClassName);
     TypeName.append("::*");
-    Name = CVTD.saveName(TypeName);
+    Name = saveName(TypeName);
   } else {
     SmallString<256> TypeName;
     if (Ptr.isConst())
@@ -466,14 +434,15 @@ void CVTypeDumperImpl::visitPointer(Poin
       TypeName.append("*");
 
     if (!TypeName.empty())
-      Name = CVTD.saveName(TypeName);
+      Name = saveName(TypeName);
   }
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitModifier(ModifierRecord &Mod) {
+Error CVTypeDumper::visitModifier(ModifierRecord &Mod) {
   uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
   printTypeIndex("ModifiedType", Mod.getModifiedType());
-  W.printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
+  W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
 
   StringRef ModifiedName = getTypeName(Mod.getModifiedType());
   SmallString<256> TypeName;
@@ -484,146 +453,162 @@ void CVTypeDumperImpl::visitModifier(Mod
   if (Mods & uint16_t(ModifierOptions::Unaligned))
     TypeName.append("__unaligned ");
   TypeName.append(ModifiedName);
-  Name = CVTD.saveName(TypeName);
+  Name = saveName(TypeName);
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitBitField(BitFieldRecord &BitField) {
+Error CVTypeDumper::visitBitField(BitFieldRecord &BitField) {
   printTypeIndex("Type", BitField.getType());
-  W.printNumber("BitSize", BitField.getBitSize());
-  W.printNumber("BitOffset", BitField.getBitOffset());
+  W->printNumber("BitSize", BitField.getBitSize());
+  W->printNumber("BitOffset", BitField.getBitOffset());
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitVFTableShape(VFTableShapeRecord &Shape) {
-  W.printNumber("VFEntryCount", Shape.getEntryCount());
+Error CVTypeDumper::visitVFTableShape(VFTableShapeRecord &Shape) {
+  W->printNumber("VFEntryCount", Shape.getEntryCount());
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitUdtSourceLine(UdtSourceLineRecord &Line) {
+Error CVTypeDumper::visitUdtSourceLine(UdtSourceLineRecord &Line) {
   printTypeIndex("UDT", Line.getUDT());
   printTypeIndex("SourceFile", Line.getSourceFile());
-  W.printNumber("LineNumber", Line.getLineNumber());
+  W->printNumber("LineNumber", Line.getLineNumber());
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitUdtModSourceLine(UdtModSourceLineRecord &Line) {
+Error CVTypeDumper::visitUdtModSourceLine(UdtModSourceLineRecord &Line) {
   printTypeIndex("UDT", Line.getUDT());
   printTypeIndex("SourceFile", Line.getSourceFile());
-  W.printNumber("LineNumber", Line.getLineNumber());
-  W.printNumber("Module", Line.getModule());
+  W->printNumber("LineNumber", Line.getLineNumber());
+  W->printNumber("Module", Line.getModule());
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitBuildInfo(BuildInfoRecord &Args) {
-  W.printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
+Error CVTypeDumper::visitBuildInfo(BuildInfoRecord &Args) {
+  W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
 
-  ListScope Arguments(W, "Arguments");
+  ListScope Arguments(*W, "Arguments");
   for (auto Arg : Args.getArgs()) {
     printTypeIndex("ArgType", Arg);
   }
+  return Error::success();
 }
 
-void CVTypeDumperImpl::printMemberAttributes(MemberAttributes Attrs) {
+void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) {
   return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
                                Attrs.getFlags());
 }
 
-void CVTypeDumperImpl::printMemberAttributes(MemberAccess Access,
-                                             MethodKind Kind,
-                                             MethodOptions Options) {
-  W.printEnum("AccessSpecifier", uint8_t(Access),
-              makeArrayRef(MemberAccessNames));
+void CVTypeDumper::printMemberAttributes(MemberAccess Access, MethodKind Kind,
+                                         MethodOptions Options) {
+  W->printEnum("AccessSpecifier", uint8_t(Access),
+               makeArrayRef(MemberAccessNames));
   // Data members will be vanilla. Don't try to print a method kind for them.
   if (Kind != MethodKind::Vanilla)
-    W.printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
+    W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
   if (Options != MethodOptions::None) {
-    W.printFlags("MethodOptions", unsigned(Options),
-                 makeArrayRef(MethodOptionNames));
+    W->printFlags("MethodOptions", unsigned(Options),
+                  makeArrayRef(MethodOptionNames));
   }
 }
 
-void CVTypeDumperImpl::visitUnknownMember(TypeLeafKind Leaf) {
-  W.printHex("UnknownMember", unsigned(Leaf));
+Error CVTypeDumper::visitUnknownMember(const CVRecord<TypeLeafKind> &Record) {
+  W->printHex("UnknownMember", unsigned(Record.Type));
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) {
-  DictScope S(W, "UnknownType");
-  W.printEnum("Kind", uint16_t(Rec.Type), makeArrayRef(LeafTypeNames));
-  W.printNumber("Length", uint32_t(Rec.Data.size()));
+Error CVTypeDumper::visitUnknownType(const CVRecord<TypeLeafKind> &Record) {
+  DictScope S(*W, "UnknownType");
+  W->printEnum("Kind", uint16_t(Record.Type), makeArrayRef(LeafTypeNames));
+  W->printNumber("Length", uint32_t(Record.Data.size()));
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitNestedType(NestedTypeRecord &Nested) {
-  DictScope S(W, "NestedType");
+Error CVTypeDumper::visitNestedType(NestedTypeRecord &Nested) {
+  DictScope S(*W, "NestedType");
   printTypeIndex("Type", Nested.getNestedType());
-  W.printString("Name", Nested.getName());
+  W->printString("Name", Nested.getName());
   Name = Nested.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitOneMethod(OneMethodRecord &Method) {
-  DictScope S(W, "OneMethod");
+Error CVTypeDumper::visitOneMethod(OneMethodRecord &Method) {
+  DictScope S(*W, "OneMethod");
   MethodKind K = Method.getKind();
   printMemberAttributes(Method.getAccess(), K, Method.getOptions());
   printTypeIndex("Type", Method.getType());
   // If virtual, then read the vftable offset.
   if (Method.isIntroducingVirtual())
-    W.printHex("VFTableOffset", Method.getVFTableOffset());
-  W.printString("Name", Method.getName());
+    W->printHex("VFTableOffset", Method.getVFTableOffset());
+  W->printString("Name", Method.getName());
   Name = Method.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitOverloadedMethod(OverloadedMethodRecord &Method) {
-  DictScope S(W, "OverloadedMethod");
-  W.printHex("MethodCount", Method.getNumOverloads());
+Error CVTypeDumper::visitOverloadedMethod(OverloadedMethodRecord &Method) {
+  DictScope S(*W, "OverloadedMethod");
+  W->printHex("MethodCount", Method.getNumOverloads());
   printTypeIndex("MethodListIndex", Method.getMethodList());
-  W.printString("Name", Method.getName());
+  W->printString("Name", Method.getName());
   Name = Method.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitDataMember(DataMemberRecord &Field) {
-  DictScope S(W, "DataMember");
+Error CVTypeDumper::visitDataMember(DataMemberRecord &Field) {
+  DictScope S(*W, "DataMember");
   printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
                         MethodOptions::None);
   printTypeIndex("Type", Field.getType());
-  W.printHex("FieldOffset", Field.getFieldOffset());
-  W.printString("Name", Field.getName());
+  W->printHex("FieldOffset", Field.getFieldOffset());
+  W->printString("Name", Field.getName());
   Name = Field.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitStaticDataMember(StaticDataMemberRecord &Field) {
-  DictScope S(W, "StaticDataMember");
+Error CVTypeDumper::visitStaticDataMember(StaticDataMemberRecord &Field) {
+  DictScope S(*W, "StaticDataMember");
   printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
                         MethodOptions::None);
   printTypeIndex("Type", Field.getType());
-  W.printString("Name", Field.getName());
+  W->printString("Name", Field.getName());
   Name = Field.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitVFPtr(VFPtrRecord &VFTable) {
-  DictScope S(W, "VFPtr");
+Error CVTypeDumper::visitVFPtr(VFPtrRecord &VFTable) {
+  DictScope S(*W, "VFPtr");
   printTypeIndex("Type", VFTable.getType());
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitEnumerator(EnumeratorRecord &Enum) {
-  DictScope S(W, "Enumerator");
+Error CVTypeDumper::visitEnumerator(EnumeratorRecord &Enum) {
+  DictScope S(*W, "Enumerator");
   printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
                         MethodOptions::None);
-  W.printNumber("EnumValue", Enum.getValue());
-  W.printString("Name", Enum.getName());
+  W->printNumber("EnumValue", Enum.getValue());
+  W->printString("Name", Enum.getName());
   Name = Enum.getName();
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitBaseClass(BaseClassRecord &Base) {
-  DictScope S(W, "BaseClass");
+Error CVTypeDumper::visitBaseClass(BaseClassRecord &Base) {
+  DictScope S(*W, "BaseClass");
   printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
                         MethodOptions::None);
   printTypeIndex("BaseType", Base.getBaseType());
-  W.printHex("BaseOffset", Base.getBaseOffset());
+  W->printHex("BaseOffset", Base.getBaseOffset());
+  return Error::success();
 }
 
-void CVTypeDumperImpl::visitVirtualBaseClass(VirtualBaseClassRecord &Base) {
-  DictScope S(W, "VirtualBaseClass");
+Error CVTypeDumper::visitVirtualBaseClass(VirtualBaseClassRecord &Base) {
+  DictScope S(*W, "VirtualBaseClass");
   printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
                         MethodOptions::None);
   printTypeIndex("BaseType", Base.getBaseType());
   printTypeIndex("VBPtrType", Base.getVBPtrType());
-  W.printHex("VBPtrOffset", Base.getVBPtrOffset());
-  W.printHex("VBTableIndex", Base.getVTableIndex());
+  W->printHex("VBPtrOffset", Base.getVBPtrOffset());
+  W->printHex("VBTableIndex", Base.getVTableIndex());
+  return Error::success();
 }
 
 StringRef CVTypeDumper::getTypeName(TypeIndex TI) {
@@ -663,28 +648,29 @@ void CVTypeDumper::printTypeIndex(String
     W->printHex(FieldName, TI.getIndex());
 }
 
-bool CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) {
+Error CVTypeDumper::dump(const CVRecord<TypeLeafKind> &Record) {
   assert(W && "printer should not be null");
-  CVTypeDumperImpl Dumper(*this, *W, PrintRecordBytes);
-  Dumper.visitTypeRecord(Record);
-  return !Dumper.hadError();
+  CVTypeVisitor Visitor(*this);
+
+  if (auto EC = Visitor.visitTypeRecord(Record))
+    return EC;
+  return Error::success();
 }
 
-bool CVTypeDumper::dump(const CVTypeArray &Types) {
+Error CVTypeDumper::dump(const CVTypeArray &Types) {
   assert(W && "printer should not be null");
-  CVTypeDumperImpl Dumper(*this, *W, PrintRecordBytes);
-  Dumper.visitTypeStream(Types);
-  return !Dumper.hadError();
+  CVTypeVisitor Visitor(*this);
+  if (auto EC = Visitor.visitTypeStream(Types))
+    return EC;
+  return Error::success();
 }
 
-bool CVTypeDumper::dump(ArrayRef<uint8_t> Data) {
+Error CVTypeDumper::dump(ArrayRef<uint8_t> Data) {
   ByteStream<> Stream(Data);
   CVTypeArray Types;
   StreamReader Reader(Stream);
-  if (auto EC = Reader.readArray(Types, Reader.getLength())) {
-    consumeError(std::move(EC));
-    return false;
-  }
+  if (auto EC = Reader.readArray(Types, Reader.getLength()))
+    return EC;
 
   return dump(Types);
 }

Modified: llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp Thu Jun 16 13:22:27 2016
@@ -15,6 +15,8 @@
 #include "llvm/DebugInfo/CodeView/StreamRef.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/ScopedPrinter.h"
 
 using namespace llvm;
@@ -49,32 +51,32 @@ namespace {
 /// - If the type record already exists in the destination stream, discard it
 ///   and update the type index map to forward the source type index to the
 ///   existing destination type index.
-class TypeStreamMerger : public CVTypeVisitor<TypeStreamMerger> {
+class TypeStreamMerger : public TypeVisitorCallbacks {
 public:
   TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) {
     assert(!hadError());
   }
 
-  /// CVTypeVisitor overrides.
+/// TypeVisitorCallbacks overrides.
 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
-  void visit##Name(Name##Record &Record);
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+  Error visit##Name(Name##Record &Record) override;
 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  void visit##Name(Name##Record &Record);
+  TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
 
-  void visitUnknownType(const CVRecord<TypeLeafKind> &Record);
+  Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override;
 
-  void visitTypeBegin(const CVRecord<TypeLeafKind> &Record);
-  void visitTypeEnd(const CVRecord<TypeLeafKind> &Record);
+  Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
+  Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override;
 
-  void visitFieldList(TypeLeafKind Leaf, ArrayRef<uint8_t> FieldData);
+  Error visitFieldListEnd(const CVRecord<TypeLeafKind> &Record) override;
 
   bool mergeStream(const CVTypeArray &Types);
 
 private:
-  bool hadError() { return FoundBadTypeIndex || CVTypeVisitor::hadError(); }
+  bool hadError() { return FoundBadTypeIndex; }
 
   bool FoundBadTypeIndex = false;
 
@@ -91,45 +93,52 @@ private:
 
 } // end anonymous namespace
 
-void TypeStreamMerger::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) {
+Error TypeStreamMerger::visitTypeBegin(const CVRecord<TypeLeafKind> &Rec) {
   BeginIndexMapSize = IndexMap.size();
+  return Error::success();
 }
 
-void TypeStreamMerger::visitTypeEnd(const CVRecord<TypeLeafKind> &Rec) {
+Error TypeStreamMerger::visitTypeEnd(const CVRecord<TypeLeafKind> &Rec) {
   assert(IndexMap.size() == BeginIndexMapSize + 1);
+  return Error::success();
 }
 
-void TypeStreamMerger::visitFieldList(TypeLeafKind Leaf,
-                                      ArrayRef<uint8_t> FieldData) {
-  CVTypeVisitor::visitFieldList(Leaf, FieldData);
+Error TypeStreamMerger::visitFieldListEnd(const CVRecord<TypeLeafKind> &Rec) {
   IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
   FieldBuilder.reset();
+  return Error::success();
 }
 
 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
-  void TypeStreamMerger::visit##Name(Name##Record &Record) {                   \
+  Error TypeStreamMerger::visit##Name(Name##Record &Record) {                  \
     FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);                   \
     IndexMap.push_back(DestStream.write##Name(Record));                        \
+    return Error::success();                                                   \
   }
 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  void TypeStreamMerger::visit##Name(Name##Record &Record) {                   \
+  Error TypeStreamMerger::visit##Name(Name##Record &Record) {                  \
     FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap);                   \
     FieldBuilder.write##Name(Record);                                          \
+    return Error::success();                                                   \
   }
 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
 
-void TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) {
+Error TypeStreamMerger::visitUnknownType(const CVRecord<TypeLeafKind> &Rec) {
   // We failed to translate a type. Translate this index as "not translated".
   IndexMap.push_back(
       TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct));
-  parseError();
+  return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record);
 }
 
 bool TypeStreamMerger::mergeStream(const CVTypeArray &Types) {
   assert(IndexMap.empty());
-  visitTypeStream(Types);
+  CVTypeVisitor Visitor(*this);
+  if (auto EC = Visitor.visitTypeStream(Types)) {
+    consumeError(std::move(EC));
+    return false;
+  }
   IndexMap.clear();
   return !hadError();
 }

Modified: llvm/trunk/lib/DebugInfo/PDB/Raw/RawError.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/PDB/Raw/RawError.cpp?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/RawError.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/RawError.cpp Thu Jun 16 13:22:27 2016
@@ -32,6 +32,8 @@ public:
       return "The specified block address is not valid.";
     case raw_error_code::not_writable:
       return "The PDB does not support writing.";
+    case raw_error_code::invalid_tpi_hash:
+      return "The Type record has an invalid hash value.";
     }
     llvm_unreachable("Unrecognized raw_error_code");
   }

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=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp Thu Jun 16 13:22:27 2016
@@ -84,39 +84,44 @@ template <typename T> static uint32_t ge
 }
 
 namespace {
-class TpiHashVerifier : public CVTypeVisitor<TpiHashVerifier> {
+class TpiHashVerifier : public TypeVisitorCallbacks {
 public:
   TpiHashVerifier(FixedStreamArray<support::ulittle32_t> &HashValues,
                   uint32_t NumHashBuckets)
       : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {}
 
-  void visitUdtSourceLine(UdtSourceLineRecord &Rec) { verifySourceLine(Rec); }
-
-  void visitUdtModSourceLine(UdtModSourceLineRecord &Rec) {
-    verifySourceLine(Rec);
+  Error visitUdtSourceLine(UdtSourceLineRecord &Rec) override {
+    return verifySourceLine(Rec);
   }
 
-  void visitClass(ClassRecord &Rec) { verify(Rec); }
-  void visitEnum(EnumRecord &Rec) { verify(Rec); }
-  void visitInterface(ClassRecord &Rec) { verify(Rec); }
-  void visitStruct(ClassRecord &Rec) { verify(Rec); }
-  void visitUnion(UnionRecord &Rec) { verify(Rec); }
+  Error visitUdtModSourceLine(UdtModSourceLineRecord &Rec) override {
+    return verifySourceLine(Rec);
+  }
 
-  void visitTypeEnd(const CVRecord<TypeLeafKind> &Record) { ++Index; }
+  Error visitClass(ClassRecord &Rec) override { return verify(Rec); }
+  Error visitEnum(EnumRecord &Rec) override { return verify(Rec); }
+  Error visitUnion(UnionRecord &Rec) override { return verify(Rec); }
+
+  Error visitTypeEnd(const CVRecord<TypeLeafKind> &Record) override {
+    ++Index;
+    return Error::success();
+  }
 
 private:
-  template <typename T> void verify(T &Rec) {
+  template <typename T> Error verify(T &Rec) {
     uint32_t Hash = getTpiHash(Rec);
     if (Hash && Hash % NumHashBuckets != HashValues[Index])
-      parseError();
+      return make_error<RawError>(raw_error_code::invalid_tpi_hash);
+    return Error::success();
   }
 
-  template <typename T> void verifySourceLine(T &Rec) {
+  template <typename T> Error verifySourceLine(T &Rec) {
     char Buf[4];
     support::endian::write32le(Buf, Rec.getUDT().getIndex());
     uint32_t Hash = hashStringV1(StringRef(Buf, 4));
     if (Hash % NumHashBuckets != HashValues[Index])
-      parseError();
+      return make_error<RawError>(raw_error_code::invalid_tpi_hash);
+    return Error::success();
   }
 
   FixedStreamArray<support::ulittle32_t> HashValues;
@@ -129,11 +134,8 @@ private:
 // Currently we only verify SRC_LINE records.
 Error TpiStream::verifyHashValues() {
   TpiHashVerifier Verifier(HashValues, Header->NumHashBuckets);
-  Verifier.visitTypeStream(TypeRecords);
-  if (Verifier.hadError())
-    return make_error<RawError>(raw_error_code::corrupt_file,
-                                "Corrupt TPI hash table.");
-  return Error::success();
+  CVTypeVisitor Visitor(Verifier);
+  return Visitor.visitTypeStream(TypeRecords);
 }
 
 Error TpiStream::reload() {

Modified: llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp (original)
+++ llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp Thu Jun 16 13:22:27 2016
@@ -328,8 +328,10 @@ Error LLVMOutputStyle::dumpTpiStream(uin
     for (auto &Type : Tpi->types(&HadError)) {
       DictScope DD(P, "");
 
-      if (DumpRecords)
-        TD.dump(Type);
+      if (DumpRecords) {
+        if (auto EC = TD.dump(Type))
+          return EC;
+      }
 
       if (DumpRecordBytes)
         P.printBinaryBlock("Bytes", Type.Data);
@@ -347,8 +349,10 @@ Error LLVMOutputStyle::dumpTpiStream(uin
     TD.setPrinter(nullptr);
 
     bool HadError = false;
-    for (auto &Type : Tpi->types(&HadError))
-      TD.dump(Type);
+    for (auto &Type : Tpi->types(&HadError)) {
+      if (auto EC = TD.dump(Type))
+        return EC;
+    }
 
     TD.setPrinter(OldP);
     dumpTpiHash(P, *Tpi);

Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=272929&r1=272928&r2=272929&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Thu Jun 16 13:22:27 2016
@@ -1108,9 +1108,9 @@ void COFFDumper::printCodeViewTypeSectio
   if (Magic != COFF::DEBUG_SECTION_MAGIC)
     return error(object_error::parse_failed);
 
-  if (!CVTD.dump({Data.bytes_begin(), Data.bytes_end()})) {
+  if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()})) {
     W.flush();
-    error(object_error::parse_failed);
+    error(llvm::errorToErrorCode(std::move(EC)));
   }
 }
 
@@ -1555,8 +1555,8 @@ void llvm::dumpCodeViewMergedTypes(
     Buf.append(Record.begin(), Record.end());
   });
   CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes);
-  if (!CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()})) {
+  if (auto EC = CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()})) {
     Writer.flush();
-    error(object_error::parse_failed);
+    error(llvm::errorToErrorCode(std::move(EC)));
   }
 }




More information about the llvm-commits mailing list