]> granicus.if.org Git - llvm/commitdiff
[CodeView] Finish decoupling TypeDatabase from TypeDumper.
authorZachary Turner <zturner@google.com>
Wed, 11 Jan 2017 23:24:22 +0000 (23:24 +0000)
committerZachary Turner <zturner@google.com>
Wed, 11 Jan 2017 23:24:22 +0000 (23:24 +0000)
Previously the type dumper itself was passed around to a lot of different
places and manipulated in ways that were more appropriate on the type
database. For example, the entire TypeDumper was passed into the symbol
dumper, when all the symbol dumper wanted to do was lookup the name of a
TypeIndex so it could print it. That's what the TypeDatabase is for --
mapping type indices to names.

Another example is how if the user runs llvm-pdbdump with the option to
dump symbols but not types, we still have to visit all types so that we
can print minimal information about the type of a symbol, but just without
dumping full symbol records. The way we did this before is by hacking it
up so that we run everything through the type dumper with a null printer,
so that the output goes to /dev/null. But really, we don't need to dump
anything, all we want to do is build the type database. Since
TypeDatabaseVisitor now exists independently of TypeDumper, we can do
this. We just build a custom visitor callback pipeline that includes a
database visitor but not a dumper.

All the hackery around printers etc goes away. After this patch, we could
probably even delete the entire CVTypeDumper class since really all it is
at this point is a thin wrapper that hides the details of how to build a
useful visitation pipeline. It's not a priority though, so CVTypeDumper
remains for now.

After this patch we will be able to easily plug in a different style of
type dumper by only implementing the proper visitation methods to dump
one-line output and then sticking it on the pipeline.

Differential Revision: https://reviews.llvm.org/D28524

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291724 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/DebugInfo/CodeView/CVTypeDumper.h
include/llvm/DebugInfo/CodeView/SymbolDumper.h
include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h [new file with mode: 0644]
lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
lib/DebugInfo/CodeView/CMakeLists.txt
lib/DebugInfo/CodeView/CVTypeDumper.cpp
lib/DebugInfo/CodeView/SymbolDumper.cpp
lib/DebugInfo/CodeView/TypeDumpVisitor.cpp [new file with mode: 0644]
tools/llvm-pdbdump/LLVMOutputStyle.cpp
tools/llvm-pdbdump/LLVMOutputStyle.h
tools/llvm-readobj/COFFDumper.cpp

index 482bade15784d6753a8e09d6a3c218fd7e0730fe..e1dd6a10b5a16dc112b910d9a3dd43027d7e8dc9 100644 (file)
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/ScopedPrinter.h"
 
 namespace llvm {
-class ScopedPrinter;
 
 namespace codeview {
 
 /// Dumper for CodeView type streams found in COFF object files and PDB files.
-class CVTypeDumper : public TypeVisitorCallbacks {
+class CVTypeDumper {
 public:
-  CVTypeDumper(ScopedPrinter *W, bool PrintRecordBytes)
-      : W(W), PrintRecordBytes(PrintRecordBytes) {}
-
-  void printTypeIndex(StringRef FieldName, TypeIndex TI);
+  explicit CVTypeDumper(TypeDatabase &TypeDB) : TypeDB(TypeDB) {}
 
   /// Dumps one type record.  Returns false if there was a type parsing error,
   /// and true otherwise.  This should be called in order, since the dumper
   /// maintains state about previous records which are necessary for cross
   /// type references.
-  Error dump(const CVRecord<TypeLeafKind> &Record);
+  Error dump(const CVType &Record, TypeVisitorCallbacks &Dumper);
 
   /// Dumps the type records in Types. Returns false if there was a type stream
   /// parse error, and true otherwise.
-  Error dump(const CVTypeArray &Types);
+  Error dump(const CVTypeArray &Types, TypeVisitorCallbacks &Dumper);
 
   /// 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.
-  Error dump(ArrayRef<uint8_t> Data);
-
-  void setPrinter(ScopedPrinter *P);
-  ScopedPrinter *getPrinter() { return W; }
-
-  /// Action to take on unknown types. By default, they are ignored.
-  Error visitUnknownType(CVType &Record) override;
-  Error visitUnknownMember(CVMemberRecord &Record) override;
-
-  /// Paired begin/end actions for all types. Receives all record data,
-  /// including the fixed-length record prefix.
-  Error visitTypeBegin(CVType &Record) override;
-  Error visitTypeEnd(CVType &Record) override;
-  Error visitMemberBegin(CVMemberRecord &Record) override;
-  Error visitMemberEnd(CVMemberRecord &Record) override;
+  Error dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper);
 
-#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
-  Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
-#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
-  Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "TypeRecords.def"
+  static void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
+                             TypeIndex TI, TypeDatabase &DB);
 
 private:
-  void printMemberAttributes(MemberAttributes Attrs);
-  void printMemberAttributes(MemberAccess Access, MethodKind Kind,
-                             MethodOptions Options);
-
-  ScopedPrinter *W;
-
-  bool PrintRecordBytes = false;
-
-  TypeDatabase TypeDB;
+  TypeDatabase &TypeDB;
 };
 
 } // end namespace codeview
index eb63f7895a1e504b4a57aeb75a86d3aac10b77d6..a5419b37e7761a1e586eeed278efc80be504ef83 100644 (file)
@@ -20,15 +20,15 @@ namespace llvm {
 class ScopedPrinter;
 
 namespace codeview {
-class CVTypeDumper;
+class TypeDatabase;
 
 /// Dumper for CodeView symbol streams found in COFF object files and PDB files.
 class CVSymbolDumper {
 public:
-  CVSymbolDumper(ScopedPrinter &W, CVTypeDumper &CVTD,
+  CVSymbolDumper(ScopedPrinter &W, TypeDatabase &TypeDB,
                  std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
                  bool PrintRecordBytes)
-      : W(W), CVTD(CVTD), ObjDelegate(std::move(ObjDelegate)),
+      : W(W), TypeDB(TypeDB), ObjDelegate(std::move(ObjDelegate)),
         PrintRecordBytes(PrintRecordBytes) {}
 
   /// Dumps one type record.  Returns false if there was a type parsing error,
@@ -43,7 +43,7 @@ public:
 
 private:
   ScopedPrinter &W;
-  CVTypeDumper &CVTD;
+  TypeDatabase &TypeDB;
   std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
 
   bool PrintRecordBytes;
diff --git a/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h b/include/llvm/DebugInfo/CodeView/TypeDumpVisitor.h
new file mode 100644 (file)
index 0000000..a466e42
--- /dev/null
@@ -0,0 +1,67 @@
+//===-- TypeDumpVisitor.h - CodeView type info dumper -----------*- 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_TYPEDUMPVISITOR_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPVISITOR_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+namespace llvm {
+class ScopedPrinter;
+
+namespace codeview {
+
+/// Dumper for CodeView type streams found in COFF object files and PDB files.
+class TypeDumpVisitor : public TypeVisitorCallbacks {
+public:
+  TypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W, bool PrintRecordBytes)
+      : W(W), PrintRecordBytes(PrintRecordBytes), TypeDB(TypeDB) {}
+
+  void printTypeIndex(StringRef FieldName, TypeIndex TI) const;
+
+  /// Action to take on unknown types. By default, they are ignored.
+  Error visitUnknownType(CVType &Record) override;
+  Error visitUnknownMember(CVMemberRecord &Record) override;
+
+  /// Paired begin/end actions for all types. Receives all record data,
+  /// including the fixed-length record prefix.
+  Error visitTypeBegin(CVType &Record) override;
+  Error visitTypeEnd(CVType &Record) override;
+  Error visitMemberBegin(CVMemberRecord &Record) override;
+  Error visitMemberEnd(CVMemberRecord &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
+  Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override;
+#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;
+
+  TypeDatabase &TypeDB;
+};
+
+} // end namespace codeview
+} // end namespace llvm
+
+#endif
index d63a8e8580fb5e342bb0fe3d88863daed492f6dd..83440513225c127df366b8fde289701337d53812 100644 (file)
@@ -19,6 +19,7 @@
 #include "llvm/DebugInfo/CodeView/Line.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
@@ -468,7 +469,8 @@ void CodeViewDebug::emitTypeInformation() {
     CommentPrefix += ' ';
   }
 
-  CVTypeDumper CVTD(nullptr, /*PrintRecordBytes=*/false);
+  TypeDatabase TypeDB;
+  CVTypeDumper CVTD(TypeDB);
   TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef<uint8_t> Record) {
     if (OS.isVerboseAsm()) {
       // Emit a block comment describing the type record for readability.
@@ -476,8 +478,8 @@ void CodeViewDebug::emitTypeInformation() {
       raw_svector_ostream CommentOS(CommentBlock);
       ScopedPrinter SP(CommentOS);
       SP.setPrefix(CommentPrefix);
-      CVTD.setPrinter(&SP);
-      Error E = CVTD.dump(Record);
+      TypeDumpVisitor TDV(TypeDB, &SP, false);
+      Error E = CVTD.dump(Record, TDV);
       if (E) {
         logAllUnhandledErrors(std::move(E), errs(), "error: ");
         llvm_unreachable("produced malformed type record");
index 32a73fc6742aacd96318686025b6adc120c9ffed..f9bff86b41c83c388bf40bd284e80ef9c2c3c487 100644 (file)
@@ -13,6 +13,7 @@ add_llvm_library(LLVMDebugInfoCodeView
   SymbolDumper.cpp
   TypeDatabase.cpp
   TypeDatabaseVisitor.cpp
+  TypeDumpVisitor.cpp
   TypeRecord.cpp
   TypeRecordMapping.cpp
   TypeSerializer.cpp
index a652d3b983af0b6dfcc980a92cd936e2c9180c63..fcd239cce0dd39cf85b5e46b90aad888b291e3c0 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
-#include "llvm/ADT/SmallString.h"
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/TypeDatabase.h"
 #include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
 #include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/MSF/ByteStream.h"
-#include "llvm/Support/ScopedPrinter.h"
 
 using namespace llvm;
 using namespace llvm::codeview;
 
-static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
-#define CV_TYPE(enum, val) {#enum, enum},
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-};
-
-#define ENUM_ENTRY(enum_class, enum)                                           \
-  { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
-
-static const EnumEntry<uint16_t> ClassOptionNames[] = {
-    ENUM_ENTRY(ClassOptions, Packed),
-    ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
-    ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
-    ENUM_ENTRY(ClassOptions, Nested),
-    ENUM_ENTRY(ClassOptions, ContainsNestedClass),
-    ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
-    ENUM_ENTRY(ClassOptions, HasConversionOperator),
-    ENUM_ENTRY(ClassOptions, ForwardReference),
-    ENUM_ENTRY(ClassOptions, Scoped),
-    ENUM_ENTRY(ClassOptions, HasUniqueName),
-    ENUM_ENTRY(ClassOptions, Sealed),
-    ENUM_ENTRY(ClassOptions, Intrinsic),
-};
-
-static const EnumEntry<uint8_t> MemberAccessNames[] = {
-    ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private),
-    ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public),
-};
-
-static const EnumEntry<uint16_t> MethodOptionNames[] = {
-    ENUM_ENTRY(MethodOptions, Pseudo),
-    ENUM_ENTRY(MethodOptions, NoInherit),
-    ENUM_ENTRY(MethodOptions, NoConstruct),
-    ENUM_ENTRY(MethodOptions, CompilerGenerated),
-    ENUM_ENTRY(MethodOptions, Sealed),
-};
-
-static const EnumEntry<uint16_t> MemberKindNames[] = {
-    ENUM_ENTRY(MethodKind, Vanilla),
-    ENUM_ENTRY(MethodKind, Virtual),
-    ENUM_ENTRY(MethodKind, Static),
-    ENUM_ENTRY(MethodKind, Friend),
-    ENUM_ENTRY(MethodKind, IntroducingVirtual),
-    ENUM_ENTRY(MethodKind, PureVirtual),
-    ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
-};
-
-static const EnumEntry<uint8_t> PtrKindNames[] = {
-    ENUM_ENTRY(PointerKind, Near16),
-    ENUM_ENTRY(PointerKind, Far16),
-    ENUM_ENTRY(PointerKind, Huge16),
-    ENUM_ENTRY(PointerKind, BasedOnSegment),
-    ENUM_ENTRY(PointerKind, BasedOnValue),
-    ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
-    ENUM_ENTRY(PointerKind, BasedOnAddress),
-    ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
-    ENUM_ENTRY(PointerKind, BasedOnType),
-    ENUM_ENTRY(PointerKind, BasedOnSelf),
-    ENUM_ENTRY(PointerKind, Near32),
-    ENUM_ENTRY(PointerKind, Far32),
-    ENUM_ENTRY(PointerKind, Near64),
-};
-
-static const EnumEntry<uint8_t> PtrModeNames[] = {
-    ENUM_ENTRY(PointerMode, Pointer),
-    ENUM_ENTRY(PointerMode, LValueReference),
-    ENUM_ENTRY(PointerMode, PointerToDataMember),
-    ENUM_ENTRY(PointerMode, PointerToMemberFunction),
-    ENUM_ENTRY(PointerMode, RValueReference),
-};
-
-static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
-    ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
-    ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
-    ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
-    ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
-    ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
-    ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
-    ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
-    ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
-    ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
-};
-
-static const EnumEntry<uint16_t> TypeModifierNames[] = {
-    ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile),
-    ENUM_ENTRY(ModifierOptions, Unaligned),
-};
-
-static const EnumEntry<uint8_t> CallingConventions[] = {
-    ENUM_ENTRY(CallingConvention, NearC),
-    ENUM_ENTRY(CallingConvention, FarC),
-    ENUM_ENTRY(CallingConvention, NearPascal),
-    ENUM_ENTRY(CallingConvention, FarPascal),
-    ENUM_ENTRY(CallingConvention, NearFast),
-    ENUM_ENTRY(CallingConvention, FarFast),
-    ENUM_ENTRY(CallingConvention, NearStdCall),
-    ENUM_ENTRY(CallingConvention, FarStdCall),
-    ENUM_ENTRY(CallingConvention, NearSysCall),
-    ENUM_ENTRY(CallingConvention, FarSysCall),
-    ENUM_ENTRY(CallingConvention, ThisCall),
-    ENUM_ENTRY(CallingConvention, MipsCall),
-    ENUM_ENTRY(CallingConvention, Generic),
-    ENUM_ENTRY(CallingConvention, AlphaCall),
-    ENUM_ENTRY(CallingConvention, PpcCall),
-    ENUM_ENTRY(CallingConvention, SHCall),
-    ENUM_ENTRY(CallingConvention, ArmCall),
-    ENUM_ENTRY(CallingConvention, AM33Call),
-    ENUM_ENTRY(CallingConvention, TriCall),
-    ENUM_ENTRY(CallingConvention, SH5Call),
-    ENUM_ENTRY(CallingConvention, M32RCall),
-    ENUM_ENTRY(CallingConvention, ClrCall),
-    ENUM_ENTRY(CallingConvention, Inline),
-    ENUM_ENTRY(CallingConvention, NearVector),
-};
-
-static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
-    ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
-    ENUM_ENTRY(FunctionOptions, Constructor),
-    ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
-};
-
-#undef ENUM_ENTRY
-
-static StringRef getLeafTypeName(TypeLeafKind LT) {
-  switch (LT) {
-#define TYPE_RECORD(ename, value, name)                                        \
-  case ename:                                                                  \
-    return #name;
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
-  default:
-    break;
-  }
-  return "UnknownLeaf";
-}
-
-Error CVTypeDumper::visitTypeBegin(CVType &Record) {
-  W->startLine() << getLeafTypeName(Record.Type);
-  W->getOStream() << " (" << HexNumber(TypeDB.getNextTypeIndex().getIndex())
-                  << ")";
-  W->getOStream() << " {\n";
-  W->indent();
-  W->printEnum("TypeLeafKind", unsigned(Record.Type),
-               makeArrayRef(LeafTypeNames));
-  return Error::success();
-}
-
-Error CVTypeDumper::visitTypeEnd(CVType &Record) {
-  if (PrintRecordBytes)
-    W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content()));
-
-  W->unindent();
-  W->startLine() << "}\n";
-  return Error::success();
-}
-
-Error CVTypeDumper::visitMemberBegin(CVMemberRecord &Record) {
-  W->startLine() << getLeafTypeName(Record.Kind);
-  W->getOStream() << " {\n";
-  W->indent();
-  W->printEnum("TypeLeafKind", unsigned(Record.Kind),
-               makeArrayRef(LeafTypeNames));
-  return Error::success();
-}
-
-Error CVTypeDumper::visitMemberEnd(CVMemberRecord &Record) {
-  if (PrintRecordBytes)
-    W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
-
-  W->unindent();
-  W->startLine() << "}\n";
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, FieldListRecord &FieldList) {
-  CVTypeVisitor Visitor(*this);
-  if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data))
-    return EC;
-
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, StringIdRecord &String) {
-  printTypeIndex("Id", String.getId());
-  W->printString("StringData", String.getString());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
-  auto Indices = Args.getIndices();
-  uint32_t Size = Indices.size();
-  W->printNumber("NumArgs", Size);
-  ListScope Arguments(*W, "Arguments");
-  for (uint32_t I = 0; I < Size; ++I) {
-    printTypeIndex("ArgType", Indices[I]);
-  }
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
-  uint16_t Props = static_cast<uint16_t>(Class.getOptions());
-  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());
-  if (Props & uint16_t(ClassOptions::HasUniqueName))
-    W->printString("LinkageName", Class.getUniqueName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
-  uint16_t Props = static_cast<uint16_t>(Union.getOptions());
-  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());
-  if (Props & uint16_t(ClassOptions::HasUniqueName))
-    W->printString("LinkageName", Union.getUniqueName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
-  uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
-  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());
-  if (Props & uint16_t(ClassOptions::HasUniqueName))
-    W->printString("LinkageName", Enum.getUniqueName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
-  printTypeIndex("ElementType", AT.getElementType());
-  printTypeIndex("IndexType", AT.getIndexType());
-  W->printNumber("SizeOf", AT.getSize());
-  W->printString("Name", AT.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
-  printTypeIndex("CompleteClass", VFT.getCompleteClass());
-  printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
-  W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
-  W->printString("VFTableName", VFT.getName());
-  for (auto N : VFT.getMethodNames())
-    W->printString("MethodName", N);
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
-  printTypeIndex("ClassType", Id.getClassType());
-  printTypeIndex("FunctionType", Id.getFunctionType());
-  W->printString("Name", Id.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, 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());
-  printTypeIndex("ArgListType", Proc.getArgumentList());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, 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());
-  printTypeIndex("ArgListType", MF.getArgumentList());
-  W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR,
-                                     MethodOverloadListRecord &MethodList) {
-  for (auto &M : MethodList.getMethods()) {
-    ListScope S(*W, "Method");
-    printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
-    printTypeIndex("Type", M.getType());
-    if (M.isIntroducingVirtual())
-      W->printHex("VFTableOffset", M.getVFTableOffset());
-  }
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
-  printTypeIndex("ParentScope", Func.getParentScope());
-  printTypeIndex("FunctionType", Func.getFunctionType());
-  W->printString("Name", Func.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
-  W->printBinary("Signature", TS.getGuid());
-  W->printNumber("Age", TS.getAge());
-  W->printString("Name", TS.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, 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->printNumber("SizeOf", Ptr.getSize());
-
-  if (Ptr.isPointerToMember()) {
-    const MemberPointerInfo &MI = Ptr.getMemberInfo();
-
-    printTypeIndex("ClassType", MI.getContainingType());
-    W->printEnum("Representation", uint16_t(MI.getRepresentation()),
-                 makeArrayRef(PtrMemberRepNames));
-  }
-
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
-  uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
-  printTypeIndex("ModifiedType", Mod.getModifiedType());
-  W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
-
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) {
-  printTypeIndex("Type", BitField.getType());
-  W->printNumber("BitSize", BitField.getBitSize());
-  W->printNumber("BitOffset", BitField.getBitOffset());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, VFTableShapeRecord &Shape) {
-  W->printNumber("VFEntryCount", Shape.getEntryCount());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, UdtSourceLineRecord &Line) {
-  printTypeIndex("UDT", Line.getUDT());
-  printTypeIndex("SourceFile", Line.getSourceFile());
-  W->printNumber("LineNumber", Line.getLineNumber());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR,
-                                     UdtModSourceLineRecord &Line) {
-  printTypeIndex("UDT", Line.getUDT());
-  printTypeIndex("SourceFile", Line.getSourceFile());
-  W->printNumber("LineNumber", Line.getLineNumber());
-  W->printNumber("Module", Line.getModule());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) {
-  W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
-
-  ListScope Arguments(*W, "Arguments");
-  for (auto Arg : Args.getArgs()) {
-    printTypeIndex("ArgType", Arg);
-  }
-  return Error::success();
-}
-
-void CVTypeDumper::printMemberAttributes(MemberAttributes Attrs) {
-  return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
-                               Attrs.getFlags());
-}
-
-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));
-  if (Options != MethodOptions::None) {
-    W->printFlags("MethodOptions", unsigned(Options),
-                  makeArrayRef(MethodOptionNames));
-  }
-}
-
-Error CVTypeDumper::visitUnknownMember(CVMemberRecord &Record) {
-  W->printHex("UnknownMember", unsigned(Record.Kind));
-  return Error::success();
-}
-
-Error CVTypeDumper::visitUnknownType(CVType &Record) {
-  W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames));
-  W->printNumber("Length", uint32_t(Record.content().size()));
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     NestedTypeRecord &Nested) {
-  printTypeIndex("Type", Nested.getNestedType());
-  W->printString("Name", Nested.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     OneMethodRecord &Method) {
-  MethodKind K = Method.getMethodKind();
-  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());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     OverloadedMethodRecord &Method) {
-  W->printHex("MethodCount", Method.getNumOverloads());
-  printTypeIndex("MethodListIndex", Method.getMethodList());
-  W->printString("Name", Method.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     DataMemberRecord &Field) {
-  printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
-                        MethodOptions::None);
-  printTypeIndex("Type", Field.getType());
-  W->printHex("FieldOffset", Field.getFieldOffset());
-  W->printString("Name", Field.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     StaticDataMemberRecord &Field) {
-  printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
-                        MethodOptions::None);
-  printTypeIndex("Type", Field.getType());
-  W->printString("Name", Field.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     VFPtrRecord &VFTable) {
-  printTypeIndex("Type", VFTable.getType());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     EnumeratorRecord &Enum) {
-  printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
-                        MethodOptions::None);
-  W->printNumber("EnumValue", Enum.getValue());
-  W->printString("Name", Enum.getName());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     BaseClassRecord &Base) {
-  printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
-                        MethodOptions::None);
-  printTypeIndex("BaseType", Base.getBaseType());
-  W->printHex("BaseOffset", Base.getBaseOffset());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     VirtualBaseClassRecord &Base) {
-  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());
-  return Error::success();
-}
-
-Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR,
-                                     ListContinuationRecord &Cont) {
-  printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
-  return Error::success();
-}
-
-void CVTypeDumper::printTypeIndex(StringRef FieldName, TypeIndex TI) {
-  StringRef TypeName;
-  if (!TI.isNoneType())
-    TypeName = TypeDB.getTypeName(TI);
-  if (!TypeName.empty())
-    W->printHex(FieldName, TypeName, TI.getIndex());
-  else
-    W->printHex(FieldName, TI.getIndex());
-}
-
-Error CVTypeDumper::dump(const CVType &Record) {
-  assert(W && "printer should not be null");
+Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
   TypeDatabaseVisitor DBV(TypeDB);
   TypeDeserializer Deserializer;
   TypeVisitorCallbackPipeline Pipeline;
   Pipeline.addCallbackToPipeline(Deserializer);
   Pipeline.addCallbackToPipeline(DBV);
-  Pipeline.addCallbackToPipeline(*this);
+  Pipeline.addCallbackToPipeline(Dumper);
 
   CVTypeVisitor Visitor(Pipeline);
 
@@ -547,14 +35,14 @@ Error CVTypeDumper::dump(const CVType &Record) {
   return Error::success();
 }
 
-Error CVTypeDumper::dump(const CVTypeArray &Types) {
-  assert(W && "printer should not be null");
+Error CVTypeDumper::dump(const CVTypeArray &Types,
+                         TypeVisitorCallbacks &Dumper) {
   TypeDatabaseVisitor DBV(TypeDB);
   TypeDeserializer Deserializer;
   TypeVisitorCallbackPipeline Pipeline;
   Pipeline.addCallbackToPipeline(Deserializer);
   Pipeline.addCallbackToPipeline(DBV);
-  Pipeline.addCallbackToPipeline(*this);
+  Pipeline.addCallbackToPipeline(Dumper);
 
   CVTypeVisitor Visitor(Pipeline);
 
@@ -563,17 +51,23 @@ Error CVTypeDumper::dump(const CVTypeArray &Types) {
   return Error::success();
 }
 
-Error CVTypeDumper::dump(ArrayRef<uint8_t> Data) {
+Error CVTypeDumper::dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper) {
   msf::ByteStream Stream(Data);
   CVTypeArray Types;
   msf::StreamReader Reader(Stream);
   if (auto EC = Reader.readArray(Types, Reader.getLength()))
     return EC;
 
-  return dump(Types);
+  return dump(Types, Dumper);
 }
 
-void CVTypeDumper::setPrinter(ScopedPrinter *P) {
-  static ScopedPrinter NullP(llvm::nulls());
-  W = P ? P : &NullP;
+void CVTypeDumper::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
+                                  TypeIndex TI, TypeDatabase &DB) {
+  StringRef TypeName;
+  if (!TI.isNoneType())
+    TypeName = DB.getTypeName(TI);
+  if (!TypeName.empty())
+    Printer.printHex(FieldName, TypeName, TI.getIndex());
+  else
+    Printer.printHex(FieldName, TI.getIndex());
 }
index c17112884cb942c36a715ceaf32f424ad09a724f..fd54fba13c763627c518de5f4758a706f2ee2065 100644 (file)
@@ -32,9 +32,9 @@ namespace {
 /// the visitor out of SymbolDumper.h.
 class CVSymbolDumperImpl : public SymbolVisitorCallbacks {
 public:
-  CVSymbolDumperImpl(CVTypeDumper &CVTD, SymbolDumpDelegate *ObjDelegate,
+  CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate,
                      ScopedPrinter &W, bool PrintRecordBytes)
-      : CVTD(CVTD), ObjDelegate(ObjDelegate), W(W),
+      : TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W),
         PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
 
 /// CVSymbolVisitor overrides.
@@ -51,8 +51,9 @@ private:
   void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
                                    uint32_t RelocationOffset);
   void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
+  void printTypeIndex(StringRef FieldName, TypeIndex TI);
 
-  CVTypeDumper &CVTD;
+  TypeDatabase &TypeDB;
   SymbolDumpDelegate *ObjDelegate;
   ScopedPrinter &W;
 
@@ -80,6 +81,10 @@ void CVSymbolDumperImpl::printLocalVariableAddrGap(
   }
 }
 
+void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) {
+  CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB);
+}
+
 Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) {
   return Error::success();
 }
@@ -163,7 +168,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
   DictScope S(W, "BPRelativeSym");
 
   W.printNumber("Offset", BPRel.Offset);
-  CVTD.printTypeIndex("Type", BPRel.Type);
+  printTypeIndex("Type", BPRel.Type);
   W.printString("VarName", BPRel.Name);
   return Error::success();
 }
@@ -187,7 +192,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
                                      CallSiteInfo.CodeOffset, &LinkageName);
   }
   W.printHex("Segment", CallSiteInfo.Segment);
-  CVTD.printTypeIndex("Type", CallSiteInfo.Type);
+  printTypeIndex("Type", CallSiteInfo.Type);
   if (!LinkageName.empty())
     W.printString("LinkageName", LinkageName);
   return Error::success();
@@ -278,7 +283,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
                                            ConstantSym &Constant) {
   DictScope S(W, "Constant");
 
-  CVTD.printTypeIndex("Type", Constant.Type);
+  printTypeIndex("Type", Constant.Type);
   W.printNumber("Value", Constant.Value);
   W.printString("Name", Constant.Name);
   return Error::success();
@@ -293,7 +298,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
     ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
                                      Data.DataOffset, &LinkageName);
   }
-  CVTD.printTypeIndex("Type", Data.Type);
+  printTypeIndex("Type", Data.Type);
   W.printString("DisplayName", Data.Name);
   if (!LinkageName.empty())
     W.printString("LinkageName", LinkageName);
@@ -445,7 +450,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(
   }
   W.printHex("Segment", HeapAllocSite.Segment);
   W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize);
-  CVTD.printTypeIndex("Type", HeapAllocSite.Type);
+  printTypeIndex("Type", HeapAllocSite.Type);
   if (!LinkageName.empty())
     W.printString("LinkageName", LinkageName);
   return Error::success();
@@ -457,7 +462,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
 
   W.printHex("PtrParent", InlineSite.Parent);
   W.printHex("PtrEnd", InlineSite.End);
-  CVTD.printTypeIndex("Inlinee", InlineSite.Inlinee);
+  printTypeIndex("Inlinee", InlineSite.Inlinee);
 
   ListScope BinaryAnnotations(W, "BinaryAnnotations");
   for (auto &Annotation : InlineSite.annotations()) {
@@ -555,7 +560,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
 Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
   DictScope S(W, "Local");
 
-  CVTD.printTypeIndex("Type", Local.Type);
+  printTypeIndex("Type", Local.Type);
   W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames());
   W.printString("VarName", Local.Name);
   return Error::success();
@@ -586,7 +591,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
   W.printHex("CodeSize", Proc.CodeSize);
   W.printHex("DbgStart", Proc.DbgStart);
   W.printHex("DbgEnd", Proc.DbgEnd);
-  CVTD.printTypeIndex("FunctionType", Proc.FunctionType);
+  printTypeIndex("FunctionType", Proc.FunctionType);
   if (ObjDelegate) {
     ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(),
                                      Proc.CodeOffset, &LinkageName);
@@ -616,7 +621,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
 Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
   ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers");
   for (auto FuncID : Caller.Indices)
-    CVTD.printTypeIndex("FuncID", FuncID);
+    printTypeIndex("FuncID", FuncID);
   return Error::success();
 }
 
@@ -625,7 +630,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
   DictScope S(W, "RegRelativeSym");
 
   W.printHex("Offset", RegRel.Offset);
-  CVTD.printTypeIndex("Type", RegRel.Type);
+  printTypeIndex("Type", RegRel.Type);
   W.printHex("Register", RegRel.Register);
   W.printString("VarName", RegRel.Name);
   return Error::success();
@@ -640,7 +645,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
     ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
                                      Data.DataOffset, &LinkageName);
   }
-  CVTD.printTypeIndex("Type", Data.Type);
+  printTypeIndex("Type", Data.Type);
   W.printString("DisplayName", Data.Name);
   if (!LinkageName.empty())
     W.printString("LinkageName", LinkageName);
@@ -649,7 +654,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
 
 Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
   DictScope S(W, "UDT");
-  CVTD.printTypeIndex("Type", UDT.Type);
+  printTypeIndex("Type", UDT.Type);
   W.printString("UDTName", UDT.Name);
   return Error::success();
 }
@@ -664,7 +669,7 @@ Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
 Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
   SymbolVisitorCallbackPipeline Pipeline;
   SymbolDeserializer Deserializer(ObjDelegate.get());
-  CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes);
+  CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
 
   Pipeline.addCallbackToPipeline(Deserializer);
   Pipeline.addCallbackToPipeline(Dumper);
@@ -675,7 +680,7 @@ Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
 Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
   SymbolVisitorCallbackPipeline Pipeline;
   SymbolDeserializer Deserializer(ObjDelegate.get());
-  CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes);
+  CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
 
   Pipeline.addCallbackToPipeline(Deserializer);
   Pipeline.addCallbackToPipeline(Dumper);
diff --git a/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
new file mode 100644 (file)
index 0000000..033585b
--- /dev/null
@@ -0,0 +1,532 @@
+//===-- TypeDumpVisitor.cpp - CodeView type info dumper -----------*- 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/TypeDumpVisitor.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/MSF/ByteStream.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
+#define CV_TYPE(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+};
+
+#define ENUM_ENTRY(enum_class, enum)                                           \
+  { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+static const EnumEntry<uint16_t> ClassOptionNames[] = {
+    ENUM_ENTRY(ClassOptions, Packed),
+    ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
+    ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
+    ENUM_ENTRY(ClassOptions, Nested),
+    ENUM_ENTRY(ClassOptions, ContainsNestedClass),
+    ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
+    ENUM_ENTRY(ClassOptions, HasConversionOperator),
+    ENUM_ENTRY(ClassOptions, ForwardReference),
+    ENUM_ENTRY(ClassOptions, Scoped),
+    ENUM_ENTRY(ClassOptions, HasUniqueName),
+    ENUM_ENTRY(ClassOptions, Sealed),
+    ENUM_ENTRY(ClassOptions, Intrinsic),
+};
+
+static const EnumEntry<uint8_t> MemberAccessNames[] = {
+    ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private),
+    ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public),
+};
+
+static const EnumEntry<uint16_t> MethodOptionNames[] = {
+    ENUM_ENTRY(MethodOptions, Pseudo),
+    ENUM_ENTRY(MethodOptions, NoInherit),
+    ENUM_ENTRY(MethodOptions, NoConstruct),
+    ENUM_ENTRY(MethodOptions, CompilerGenerated),
+    ENUM_ENTRY(MethodOptions, Sealed),
+};
+
+static const EnumEntry<uint16_t> MemberKindNames[] = {
+    ENUM_ENTRY(MethodKind, Vanilla),
+    ENUM_ENTRY(MethodKind, Virtual),
+    ENUM_ENTRY(MethodKind, Static),
+    ENUM_ENTRY(MethodKind, Friend),
+    ENUM_ENTRY(MethodKind, IntroducingVirtual),
+    ENUM_ENTRY(MethodKind, PureVirtual),
+    ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
+};
+
+static const EnumEntry<uint8_t> PtrKindNames[] = {
+    ENUM_ENTRY(PointerKind, Near16),
+    ENUM_ENTRY(PointerKind, Far16),
+    ENUM_ENTRY(PointerKind, Huge16),
+    ENUM_ENTRY(PointerKind, BasedOnSegment),
+    ENUM_ENTRY(PointerKind, BasedOnValue),
+    ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
+    ENUM_ENTRY(PointerKind, BasedOnAddress),
+    ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
+    ENUM_ENTRY(PointerKind, BasedOnType),
+    ENUM_ENTRY(PointerKind, BasedOnSelf),
+    ENUM_ENTRY(PointerKind, Near32),
+    ENUM_ENTRY(PointerKind, Far32),
+    ENUM_ENTRY(PointerKind, Near64),
+};
+
+static const EnumEntry<uint8_t> PtrModeNames[] = {
+    ENUM_ENTRY(PointerMode, Pointer),
+    ENUM_ENTRY(PointerMode, LValueReference),
+    ENUM_ENTRY(PointerMode, PointerToDataMember),
+    ENUM_ENTRY(PointerMode, PointerToMemberFunction),
+    ENUM_ENTRY(PointerMode, RValueReference),
+};
+
+static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
+    ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
+    ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
+    ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
+    ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
+    ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
+    ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
+    ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
+    ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
+    ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
+};
+
+static const EnumEntry<uint16_t> TypeModifierNames[] = {
+    ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile),
+    ENUM_ENTRY(ModifierOptions, Unaligned),
+};
+
+static const EnumEntry<uint8_t> CallingConventions[] = {
+    ENUM_ENTRY(CallingConvention, NearC),
+    ENUM_ENTRY(CallingConvention, FarC),
+    ENUM_ENTRY(CallingConvention, NearPascal),
+    ENUM_ENTRY(CallingConvention, FarPascal),
+    ENUM_ENTRY(CallingConvention, NearFast),
+    ENUM_ENTRY(CallingConvention, FarFast),
+    ENUM_ENTRY(CallingConvention, NearStdCall),
+    ENUM_ENTRY(CallingConvention, FarStdCall),
+    ENUM_ENTRY(CallingConvention, NearSysCall),
+    ENUM_ENTRY(CallingConvention, FarSysCall),
+    ENUM_ENTRY(CallingConvention, ThisCall),
+    ENUM_ENTRY(CallingConvention, MipsCall),
+    ENUM_ENTRY(CallingConvention, Generic),
+    ENUM_ENTRY(CallingConvention, AlphaCall),
+    ENUM_ENTRY(CallingConvention, PpcCall),
+    ENUM_ENTRY(CallingConvention, SHCall),
+    ENUM_ENTRY(CallingConvention, ArmCall),
+    ENUM_ENTRY(CallingConvention, AM33Call),
+    ENUM_ENTRY(CallingConvention, TriCall),
+    ENUM_ENTRY(CallingConvention, SH5Call),
+    ENUM_ENTRY(CallingConvention, M32RCall),
+    ENUM_ENTRY(CallingConvention, ClrCall),
+    ENUM_ENTRY(CallingConvention, Inline),
+    ENUM_ENTRY(CallingConvention, NearVector),
+};
+
+static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
+    ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
+    ENUM_ENTRY(FunctionOptions, Constructor),
+    ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
+};
+
+#undef ENUM_ENTRY
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+  switch (LT) {
+#define TYPE_RECORD(ename, value, name)                                        \
+  case ename:                                                                  \
+    return #name;
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+  default:
+    break;
+  }
+  return "UnknownLeaf";
+}
+
+void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
+  CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB);
+}
+
+Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
+  W->startLine() << getLeafTypeName(Record.Type);
+  W->getOStream() << " (" << HexNumber(TypeDB.getNextTypeIndex().getIndex())
+                  << ")";
+  W->getOStream() << " {\n";
+  W->indent();
+  W->printEnum("TypeLeafKind", unsigned(Record.Type),
+               makeArrayRef(LeafTypeNames));
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitTypeEnd(CVType &Record) {
+  if (PrintRecordBytes)
+    W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content()));
+
+  W->unindent();
+  W->startLine() << "}\n";
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
+  W->startLine() << getLeafTypeName(Record.Kind);
+  W->getOStream() << " {\n";
+  W->indent();
+  W->printEnum("TypeLeafKind", unsigned(Record.Kind),
+               makeArrayRef(LeafTypeNames));
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
+  if (PrintRecordBytes)
+    W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
+
+  W->unindent();
+  W->startLine() << "}\n";
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+                                        FieldListRecord &FieldList) {
+  CVTypeVisitor Visitor(*this);
+  if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data))
+    return EC;
+
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) {
+  printTypeIndex("Id", String.getId());
+  W->printString("StringData", String.getString());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
+  auto Indices = Args.getIndices();
+  uint32_t Size = Indices.size();
+  W->printNumber("NumArgs", Size);
+  ListScope Arguments(*W, "Arguments");
+  for (uint32_t I = 0; I < Size; ++I) {
+    printTypeIndex("ArgType", Indices[I]);
+  }
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
+  uint16_t Props = static_cast<uint16_t>(Class.getOptions());
+  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());
+  if (Props & uint16_t(ClassOptions::HasUniqueName))
+    W->printString("LinkageName", Class.getUniqueName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
+  uint16_t Props = static_cast<uint16_t>(Union.getOptions());
+  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());
+  if (Props & uint16_t(ClassOptions::HasUniqueName))
+    W->printString("LinkageName", Union.getUniqueName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+  uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
+  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());
+  if (Props & uint16_t(ClassOptions::HasUniqueName))
+    W->printString("LinkageName", Enum.getUniqueName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+  printTypeIndex("ElementType", AT.getElementType());
+  printTypeIndex("IndexType", AT.getIndexType());
+  W->printNumber("SizeOf", AT.getSize());
+  W->printString("Name", AT.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
+  printTypeIndex("CompleteClass", VFT.getCompleteClass());
+  printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
+  W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
+  W->printString("VFTableName", VFT.getName());
+  for (auto N : VFT.getMethodNames())
+    W->printString("MethodName", N);
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
+  printTypeIndex("ClassType", Id.getClassType());
+  printTypeIndex("FunctionType", Id.getFunctionType());
+  W->printString("Name", Id.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, 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());
+  printTypeIndex("ArgListType", Proc.getArgumentList());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, 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());
+  printTypeIndex("ArgListType", MF.getArgumentList());
+  W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+                                        MethodOverloadListRecord &MethodList) {
+  for (auto &M : MethodList.getMethods()) {
+    ListScope S(*W, "Method");
+    printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
+    printTypeIndex("Type", M.getType());
+    if (M.isIntroducingVirtual())
+      W->printHex("VFTableOffset", M.getVFTableOffset());
+  }
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
+  printTypeIndex("ParentScope", Func.getParentScope());
+  printTypeIndex("FunctionType", Func.getFunctionType());
+  W->printString("Name", Func.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
+  W->printBinary("Signature", TS.getGuid());
+  W->printNumber("Age", TS.getAge());
+  W->printString("Name", TS.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, 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->printNumber("SizeOf", Ptr.getSize());
+
+  if (Ptr.isPointerToMember()) {
+    const MemberPointerInfo &MI = Ptr.getMemberInfo();
+
+    printTypeIndex("ClassType", MI.getContainingType());
+    W->printEnum("Representation", uint16_t(MI.getRepresentation()),
+                 makeArrayRef(PtrMemberRepNames));
+  }
+
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
+  uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+  printTypeIndex("ModifiedType", Mod.getModifiedType());
+  W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
+
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) {
+  printTypeIndex("Type", BitField.getType());
+  W->printNumber("BitSize", BitField.getBitSize());
+  W->printNumber("BitOffset", BitField.getBitOffset());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+                                        VFTableShapeRecord &Shape) {
+  W->printNumber("VFEntryCount", Shape.getEntryCount());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+                                        UdtSourceLineRecord &Line) {
+  printTypeIndex("UDT", Line.getUDT());
+  printTypeIndex("SourceFile", Line.getSourceFile());
+  W->printNumber("LineNumber", Line.getLineNumber());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+                                        UdtModSourceLineRecord &Line) {
+  printTypeIndex("UDT", Line.getUDT());
+  printTypeIndex("SourceFile", Line.getSourceFile());
+  W->printNumber("LineNumber", Line.getLineNumber());
+  W->printNumber("Module", Line.getModule());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) {
+  W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
+
+  ListScope Arguments(*W, "Arguments");
+  for (auto Arg : Args.getArgs()) {
+    printTypeIndex("ArgType", Arg);
+  }
+  return Error::success();
+}
+
+void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) {
+  return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
+                               Attrs.getFlags());
+}
+
+void TypeDumpVisitor::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));
+  if (Options != MethodOptions::None) {
+    W->printFlags("MethodOptions", unsigned(Options),
+                  makeArrayRef(MethodOptionNames));
+  }
+}
+
+Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) {
+  W->printHex("UnknownMember", unsigned(Record.Kind));
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitUnknownType(CVType &Record) {
+  W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames));
+  W->printNumber("Length", uint32_t(Record.content().size()));
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        NestedTypeRecord &Nested) {
+  printTypeIndex("Type", Nested.getNestedType());
+  W->printString("Name", Nested.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        OneMethodRecord &Method) {
+  MethodKind K = Method.getMethodKind();
+  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());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        OverloadedMethodRecord &Method) {
+  W->printHex("MethodCount", Method.getNumOverloads());
+  printTypeIndex("MethodListIndex", Method.getMethodList());
+  W->printString("Name", Method.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        DataMemberRecord &Field) {
+  printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+                        MethodOptions::None);
+  printTypeIndex("Type", Field.getType());
+  W->printHex("FieldOffset", Field.getFieldOffset());
+  W->printString("Name", Field.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        StaticDataMemberRecord &Field) {
+  printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+                        MethodOptions::None);
+  printTypeIndex("Type", Field.getType());
+  W->printString("Name", Field.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        VFPtrRecord &VFTable) {
+  printTypeIndex("Type", VFTable.getType());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        EnumeratorRecord &Enum) {
+  printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
+                        MethodOptions::None);
+  W->printNumber("EnumValue", Enum.getValue());
+  W->printString("Name", Enum.getName());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        BaseClassRecord &Base) {
+  printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+                        MethodOptions::None);
+  printTypeIndex("BaseType", Base.getBaseType());
+  W->printHex("BaseOffset", Base.getBaseOffset());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        VirtualBaseClassRecord &Base) {
+  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());
+  return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+                                        ListContinuationRecord &Cont) {
+  printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
+  return Error::success();
+}
index 98c67ec9ef3bf8d0b95fe9acbd4786a1f1b0ac02..629ba40b113c560cee14b91e8abefdc2058550d7 100644 (file)
 #include "LLVMOutputStyle.h"
 
 #include "llvm-pdbdump.h"
+#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/EnumTables.h"
 #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h"
 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
 #include "llvm/DebugInfo/MSF/StreamReader.h"
 #include "llvm/DebugInfo/PDB/PDBExtras.h"
@@ -83,8 +89,7 @@ static void printSectionOffset(llvm::raw_ostream &OS,
   OS << Off.Off << ", " << Off.Isect;
 }
 
-LLVMOutputStyle::LLVMOutputStyle(PDBFile &File)
-    : File(File), P(outs()), Dumper(&P, false) {}
+LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {}
 
 Error LLVMOutputStyle::dump() {
   if (auto EC = dumpFileHeaders())
@@ -519,6 +524,7 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
   if (!Tpi)
     return Tpi.takeError();
 
+  CVTypeDumper Dumper(TypeDB);
   if (DumpRecords || DumpRecordBytes) {
     DictScope D(P, Label);
 
@@ -532,7 +538,8 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
       DictScope DD(P, "");
 
       if (DumpRecords) {
-        if (auto EC = Dumper.dump(Type))
+        TypeDumpVisitor TDV(TypeDB, &P, false);
+        if (auto EC = Dumper.dump(Type, TDV))
           return EC;
       }
 
@@ -545,19 +552,23 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
                                   "TPI stream contained corrupt record");
   } else if (opts::raw::DumpModuleSyms) {
     // Even if the user doesn't want to dump type records, we still need to
-    // iterate them in order to build the list of types so that we can print
-    // them when dumping module symbols. So when they want to dump symbols
-    // but not types, use a null output stream.
-    ScopedPrinter *OldP = Dumper.getPrinter();
-    Dumper.setPrinter(nullptr);
+    // iterate them in order to build the type database. So when they want to
+    // dump symbols but not types, don't stick a dumper on the end, just build
+    // the type database.
+    TypeDatabaseVisitor DBV(TypeDB);
+    TypeDeserializer Deserializer;
+    TypeVisitorCallbackPipeline Pipeline;
+    Pipeline.addCallbackToPipeline(Deserializer);
+    Pipeline.addCallbackToPipeline(DBV);
+
+    CVTypeVisitor Visitor(Pipeline);
 
     bool HadError = false;
-    for (auto &Type : Tpi->types(&HadError)) {
-      if (auto EC = Dumper.dump(Type))
+    for (auto Type : Tpi->types(&HadError)) {
+      if (auto EC = Visitor.visitTypeRecord(Type))
         return EC;
     }
 
-    Dumper.setPrinter(OldP);
     dumpTpiHash(P, *Tpi);
     if (HadError)
       return make_error<RawError>(raw_error_code::corrupt_file,
@@ -640,7 +651,7 @@ Error LLVMOutputStyle::dumpDbiStream() {
 
         if (ShouldDumpSymbols) {
           ListScope SS(P, "Symbols");
-          codeview::CVSymbolDumper SD(P, Dumper, nullptr, false);
+          codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false);
           bool HadError = false;
           for (auto S : ModS.symbols(&HadError)) {
             DictScope LL(P, "");
@@ -865,7 +876,7 @@ Error LLVMOutputStyle::dumpPublicsStream() {
   P.printList("Section Offsets", Publics->getSectionOffsets(),
               printSectionOffset);
   ListScope L(P, "Symbols");
-  codeview::CVSymbolDumper SD(P, Dumper, nullptr, false);
+  codeview::CVSymbolDumper SD(P, TypeDB, nullptr, false);
   bool HadError = false;
   for (auto S : Publics->getSymbols(&HadError)) {
     DictScope DD(P, "");
index 9b3acac13bb8c9b4ca7423ac47843175af7a3d65..816d591f08f83e4ae85f3ba0f0d65843e02864e2 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "OutputStyle.h"
 
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
 #include "llvm/Support/ScopedPrinter.h"
 
 namespace llvm {
@@ -49,7 +49,7 @@ private:
 
   PDBFile &File;
   ScopedPrinter P;
-  codeview::CVTypeDumper Dumper;
+  codeview::TypeDatabase TypeDB;
   std::vector<std::string> StreamPurposes;
 };
 }
index 62df5b04f14988101a9eb918a3a6ff57c3ae6140..c83655fe4d223ea9cf1a824df29643e410a398d5 100644 (file)
@@ -30,6 +30,7 @@
 #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
 #include "llvm/DebugInfo/CodeView/SymbolDumper.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
@@ -64,8 +65,7 @@ class COFFDumper : public ObjDumper {
 public:
   friend class COFFObjectDumpDelegate;
   COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer)
-      : ObjDumper(Writer), Obj(Obj),
-        CVTD(&Writer, opts::CodeViewSubsectionBytes) {}
+      : ObjDumper(Writer), Obj(Obj), Writer(Writer) {}
 
   void printFileHeaders() override;
   void printSections() override;
@@ -99,7 +99,7 @@ private:
   void printFileNameForOffset(StringRef Label, uint32_t FileOffset);
   void printTypeIndex(StringRef FieldName, TypeIndex TI) {
     // Forward to CVTypeDumper for simplicity.
-    CVTD.printTypeIndex(FieldName, TI);
+    CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB);
   }
 
   void printCodeViewSymbolsSubsection(StringRef Subsection,
@@ -142,7 +142,8 @@ private:
   StringRef CVFileChecksumTable;
   StringRef CVStringTable;
 
-  CVTypeDumper CVTD;
+  ScopedPrinter &Writer;
+  TypeDatabase TypeDB;
 };
 
 class COFFObjectDumpDelegate : public SymbolDumpDelegate {
@@ -962,7 +963,8 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
   auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
                                                         SectionContents);
 
-  CVSymbolDumper CVSD(W, CVTD, std::move(CODD), opts::CodeViewSubsectionBytes);
+  CVSymbolDumper CVSD(W, TypeDB, std::move(CODD),
+                      opts::CodeViewSubsectionBytes);
   ByteStream Stream(BinaryData);
   CVSymbolArray Symbols;
   StreamReader Reader(Stream);
@@ -1106,7 +1108,9 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
   if (Magic != COFF::DEBUG_SECTION_MAGIC)
     return error(object_error::parse_failed);
 
-  if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()})) {
+  CVTypeDumper CVTD(TypeDB);
+  TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes);
+  if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) {
     W.flush();
     error(llvm::errorToErrorCode(std::move(EC)));
   }
@@ -1552,8 +1556,12 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
   CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
     Buf.append(Record.begin(), Record.end());
   });
-  CVTypeDumper CVTD(&Writer, opts::CodeViewSubsectionBytes);
-  if (auto EC = CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()})) {
+
+  TypeDatabase TypeDB;
+  CVTypeDumper CVTD(TypeDB);
+  TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
+  if (auto EC =
+          CVTD.dump({Buf.str().bytes_begin(), Buf.str().bytes_end()}, TDV)) {
     Writer.flush();
     error(llvm::errorToErrorCode(std::move(EC)));
   }