[llvm] r272926 - [pdb] Change type visitor pattern to be dynamic.

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


Author: zturner
Date: Thu Jun 16 13:00:28 2016
New Revision: 272926

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

This allows better catching of compiler errors since we can use
the override keyword to verify that methods are actually
overridden.

Also in this patch I've changed from storing a boolean Error
code everywhere to returning an llvm::Error, to propagate richer
error information up the call stack.

Reviewed By: ruiu, rnk
Differential Revision: http://reviews.llvm.org/D21410

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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h Thu Jun 16 13:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDumper.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDumper.h Thu Jun 16 13:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecords.def Thu Jun 16 13:00:28 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=272926&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h Thu Jun 16 13:00:28 2016
@@ -0,0 +1,53 @@
+//===- 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();
+  }
+
+#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=272926&r1=272925&r2=272926&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:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp (original)
+++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp Thu Jun 16 13:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt Thu Jun 16 13:00:28 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=272926&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp (added)
+++ llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp Thu Jun 16 13:00:28 2016
@@ -0,0 +1,119 @@
+//===- 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 = visitFieldList(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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeDumper.cpp Thu Jun 16 13:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeStreamMerger.cpp Thu Jun 16 13:00:28 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,30 @@ 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);
-
-  void visitTypeBegin(const CVRecord<TypeLeafKind> &Record);
-  void visitTypeEnd(const CVRecord<TypeLeafKind> &Record);
+  Error visitUnknownType(const CVRecord<TypeLeafKind> &Record) override;
 
-  void visitFieldList(TypeLeafKind Leaf, ArrayRef<uint8_t> FieldData);
+  Error visitTypeBegin(const CVRecord<TypeLeafKind> &Record) override;
+  Error visitTypeEnd(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 +91,46 @@ 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);
-}
-
-void TypeStreamMerger::visitFieldList(TypeLeafKind Leaf,
-                                      ArrayRef<uint8_t> FieldData) {
-  CVTypeVisitor::visitFieldList(Leaf, FieldData);
-  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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/RawError.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/RawError.cpp Thu Jun 16 13:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/PDB/Raw/TpiStream.cpp Thu Jun 16 13:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp (original)
+++ llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp Thu Jun 16 13:00:28 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=272926&r1=272925&r2=272926&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Thu Jun 16 13:00:28 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)));
   }
 }
 




More information about the llvm-commits mailing list