[PDB] Better native API support for pointers.
authorZachary Turner <zturner@google.com>
Sat, 29 Sep 2018 23:28:19 +0000 (23:28 +0000)
committerZachary Turner <zturner@google.com>
Sat, 29 Sep 2018 23:28:19 +0000 (23:28 +0000)
We didn't properly detect when a pointer was a member
pointer, and when that was the case we were not
properly returning class parent info.  This caused
member pointers to render incorrectly in pretty mode.
However, we didn't even have pretty tests for pointers
in native mode, so those are also added now to ensure
this.

llvm-svn: 343393

llvm/include/llvm/DebugInfo/PDB/Native/NativeTypePointer.h
llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h
llvm/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp
llvm/test/DebugInfo/PDB/Native/pdb-native-pointers.test
llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp
llvm/tools/llvm-pdbutil/PrettyTypeDumper.h
llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
llvm/tools/llvm-pdbutil/llvm-pdbutil.h

index e2f25d1..bcb7431 100644 (file)
@@ -33,6 +33,7 @@ public:
   void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields,
             PdbSymbolIdField RecurseIdFields) const override;
 
+  SymIndexId getClassParentId() const override;
   bool isConstType() const override;
   uint64_t getLength() const override;
   bool isReference() const override;
@@ -44,7 +45,12 @@ public:
   bool isVolatileType() const override;
   bool isUnalignedType() const override;
 
+  bool isSingleInheritance() const override;
+  bool isMultipleInheritance() const override;
+  bool isVirtualInheritance() const override;
+
 protected:
+  bool isMemberPointer() const;
   codeview::TypeIndex TI;
   Optional<codeview::PointerRecord> Record;
 };
index 9bc0b16..300d672 100644 (file)
@@ -25,6 +25,7 @@ public:
   void dumpRight(PDBSymDumper &Dumper) const override;
 
   FORWARD_SYMBOL_METHOD(isConstType)
+  FORWARD_SYMBOL_ID_METHOD(getClassParent)
   FORWARD_SYMBOL_METHOD(getLength)
   FORWARD_SYMBOL_ID_METHOD(getLexicalParent)
   FORWARD_SYMBOL_METHOD(isReference)
index 4545f7e..bd8ecb6 100644 (file)
@@ -37,6 +37,11 @@ void NativeTypePointer::dump(raw_ostream &OS, int Indent,
                              PdbSymbolIdField RecurseIdFields) const {
   NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
 
+  if (isMemberPointer()) {
+    dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session,
+                      PdbSymbolIdField::ClassParent, ShowIdFields,
+                      RecurseIdFields);
+  }
   dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
                     PdbSymbolIdField::LexicalParent, ShowIdFields,
                     RecurseIdFields);
@@ -50,10 +55,27 @@ void NativeTypePointer::dump(raw_ostream &OS, int Indent,
   dumpSymbolField(OS, "RValueReference", isRValueReference(), Indent);
   dumpSymbolField(OS, "reference", isReference(), Indent);
   dumpSymbolField(OS, "restrictedType", isRestrictedType(), Indent);
+  if (isMemberPointer()) {
+    if (isSingleInheritance())
+      dumpSymbolField(OS, "isSingleInheritance", 1, Indent);
+    else if (isMultipleInheritance())
+      dumpSymbolField(OS, "isMultipleInheritance", 1, Indent);
+    else if (isVirtualInheritance())
+      dumpSymbolField(OS, "isVirtualInheritance", 1, Indent);
+  }
   dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
   dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
 }
 
+SymIndexId NativeTypePointer::getClassParentId() const {
+  if (!isMemberPointer())
+    return 0;
+
+  assert(Record);
+  const MemberPointerInfo &MPI = Record->getMemberInfo();
+  return Session.getSymbolCache().findSymbolByTypeIndex(MPI.ContainingType);
+}
+
 uint64_t NativeTypePointer::getLength() const {
   if (Record)
     return Record->getSize();
@@ -133,3 +155,40 @@ bool NativeTypePointer::isUnalignedType() const {
   return (Record->getOptions() & PointerOptions::Unaligned) !=
          PointerOptions::None;
 }
+
+static inline bool isInheritanceKind(const MemberPointerInfo &MPI,
+                                     PointerToMemberRepresentation P1,
+                                     PointerToMemberRepresentation P2) {
+  return (MPI.getRepresentation() == P1 || MPI.getRepresentation() == P2);
+}
+
+bool NativeTypePointer::isSingleInheritance() const {
+  if (!isMemberPointer())
+    return false;
+  return isInheritanceKind(
+      Record->getMemberInfo(),
+      PointerToMemberRepresentation::SingleInheritanceData,
+      PointerToMemberRepresentation::SingleInheritanceFunction);
+}
+
+bool NativeTypePointer::isMultipleInheritance() const {
+  if (!isMemberPointer())
+    return false;
+  return isInheritanceKind(
+      Record->getMemberInfo(),
+      PointerToMemberRepresentation::MultipleInheritanceData,
+      PointerToMemberRepresentation::MultipleInheritanceFunction);
+}
+
+bool NativeTypePointer::isVirtualInheritance() const {
+  if (!isMemberPointer())
+    return false;
+  return isInheritanceKind(
+      Record->getMemberInfo(),
+      PointerToMemberRepresentation::VirtualInheritanceData,
+      PointerToMemberRepresentation::VirtualInheritanceFunction);
+}
+
+bool NativeTypePointer::isMemberPointer() const {
+  return isPointerToDataMember() || isPointerToMemberFunction();
+}
index 5bc739b..51dc665 100644 (file)
@@ -2,9 +2,42 @@
 ; being checked against is golden output generated by llvm-pdbutil without
 ; the -native flag.  Then we check that we generate the same output.
 
+; RUN: llvm-pdbutil pretty -native -pointers \
+; RUN:     %p/../Inputs/every-pointer.pdb | FileCheck %s --check-prefix=PRETTY
 ; RUN: llvm-pdbutil diadump -no-ids -native -pointers \
 ; RUN:     %p/../Inputs/every-pointer.pdb | FileCheck %s
 
+; PRETTY:      Pointers: (29 items)
+; PRETTY-NEXT: char**
+; PRETTY-NEXT: struct Foo*
+; PRETTY-NEXT: int&
+; PRETTY-NEXT: const int*
+; PRETTY-NEXT: volatile int*
+; PRETTY-NEXT: const volatile int*
+; PRETTY-NEXT: int*
+; PRETTY-NEXT: int*
+; PRETTY-NEXT: struct __vc_attributes::event_sourceAttribute*
+; PRETTY-NEXT: struct __vc_attributes::helper_attributes::v1_alttypeAttribute*
+; PRETTY-NEXT: struct __vc_attributes::helper_attributes::usageAttribute*
+; PRETTY-NEXT: struct __vc_attributes::threadingAttribute*
+; PRETTY-NEXT: struct __vc_attributes::aggregatableAttribute*
+; PRETTY-NEXT: struct __vc_attributes::event_receiverAttribute*
+; PRETTY-NEXT: struct __vc_attributes::moduleAttribute*
+; PRETTY-NEXT: const char*
+; PRETTY-NEXT: int&&
+; PRETTY-NEXT: struct Foo*
+; PRETTY-NEXT: void (__cdecl Foo::*)()
+; PRETTY-NEXT: int Foo::*
+; PRETTY-NEXT: int (__cdecl Foo::*)()
+; PRETTY-NEXT: void (__cdecl *)()
+; PRETTY-NEXT: unaligned struct Foo*
+; PRETTY-NEXT: struct Foo*
+; PRETTY-NEXT: const struct Foo*
+; PRETTY-NEXT: volatile struct Foo*
+; PRETTY-NEXT: const volatile struct Foo*
+; PRETTY-NEXT: struct Foo&&
+; PRETTY-NEXT: struct Foo
+
 ; CHECK:      {
 ; CHECK-NEXT:   symTag: PointerType
 ; CHECK-NEXT:   length: 8
 ; CHECK-NEXT:   constType: 0
 ; CHECK-NEXT:   isPointerToDataMember: 0
 ; CHECK-NEXT:   isPointerToMemberFunction: 1
-; FIXME:        isSingleInheritance: 1   # DIA has this property for member pointers
 ; CHECK-NEXT:   RValueReference: 0
 ; CHECK-NEXT:   reference: 0
 ; CHECK-NEXT:   restrictedType: 0
+; CHECK-NEXT:   isSingleInheritance: 1
 ; CHECK-NEXT:   unalignedType: 0
 ; CHECK-NEXT:   volatileType: 0
 ; CHECK-NEXT: }
 ; CHECK-NEXT:   RValueReference: 0
 ; CHECK-NEXT:   reference: 0
 ; CHECK-NEXT:   restrictedType: 0
-; FIXME:        isSingleInheritance: 1   # DIA has this property for member pointers
+; CHECK-NEXT:   isSingleInheritance: 1
 ; CHECK-NEXT:   unalignedType: 0
 ; CHECK-NEXT:   volatileType: 0
 ; CHECK-NEXT: }
 ; CHECK-NEXT:   RValueReference: 0
 ; CHECK-NEXT:   reference: 0
 ; CHECK-NEXT:   restrictedType: 0
-; FIXME:        isSingleInheritance: 1   # DIA has this property for member pointers
+; CHECK-NEXT:   isSingleInheritance: 1
 ; CHECK-NEXT:   unalignedType: 0
 ; CHECK-NEXT:   volatileType: 0
 ; CHECK-NEXT: }
index 9ffdcfd..093164b 100644 (file)
@@ -22,6 +22,7 @@
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
 #include "llvm/DebugInfo/PDB/UDTLayout.h"
@@ -136,43 +137,72 @@ filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
 
 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
 
-void TypeDumper::start(const PDBSymbolExe &Exe) {
-  if (opts::pretty::Enums) {
-    if (auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>()) {
-      Printer.NewLine();
-      WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
-      Printer << ": (" << Enums->getChildCount() << " items)";
-      Printer.Indent();
-      while (auto Enum = Enums->getNext())
-        Enum->dump(*this);
-      Printer.Unindent();
-    }
-  }
+template <typename T>
+static bool isTypeExcluded(LinePrinter &Printer, const T &Symbol) {
+  return false;
+}
+
+static bool isTypeExcluded(LinePrinter &Printer,
+                           const PDBSymbolTypeEnum &Enum) {
+  if (Printer.IsTypeExcluded(Enum.getName(), Enum.getLength()))
+    return true;
+  // Dump member enums when dumping their class definition.
+  if (nullptr != Enum.getClassParent())
+    return true;
+  return false;
+}
+
+static bool isTypeExcluded(LinePrinter &Printer,
+                           const PDBSymbolTypeTypedef &Typedef) {
+  return Printer.IsTypeExcluded(Typedef.getName(), Typedef.getLength());
+}
+
+template <typename SymbolT>
+static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe,
+                               TypeDumper &TD, StringRef Label) {
+  if (auto Children = Exe.findAllChildren<SymbolT>()) {
+    Printer.NewLine();
+    WithColor(Printer, PDB_ColorItem::Identifier).get() << Label;
+    Printer << ": (" << Children->getChildCount() << " items)";
+    Printer.Indent();
+    while (auto Child = Children->getNext()) {
+      if (isTypeExcluded(Printer, *Child))
+        continue;
 
-  if (opts::pretty::Funcsigs) {
-    if (auto Funcsigs = Exe.findAllChildren<PDBSymbolTypeFunctionSig>()) {
       Printer.NewLine();
-      WithColor(Printer, PDB_ColorItem::Identifier).get()
-          << "Function Signatures";
-      Printer << ": (" << Funcsigs->getChildCount() << " items)";
-      Printer.Indent();
-      while (auto FS = Funcsigs->getNext())
-        FS->dump(*this);
-      Printer.Unindent();
+      Child->dump(TD);
     }
+    Printer.Unindent();
   }
+}
 
-  if (opts::pretty::Typedefs) {
-    if (auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>()) {
-      Printer.NewLine();
-      WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
-      Printer << ": (" << Typedefs->getChildCount() << " items)";
-      Printer.Indent();
-      while (auto Typedef = Typedefs->getNext())
-        Typedef->dump(*this);
-      Printer.Unindent();
-    }
+static void printClassDecl(LinePrinter &Printer,
+                           const PDBSymbolTypeUDT &Class) {
+  if (Class.getUnmodifiedTypeId() != 0) {
+    if (Class.isConstType())
+      WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+    if (Class.isVolatileType())
+      WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+    if (Class.isUnalignedType())
+      WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned ";
   }
+  WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
+  WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
+}
+
+void TypeDumper::start(const PDBSymbolExe &Exe) {
+  if (opts::pretty::Enums)
+    dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
+
+  if (opts::pretty::Funcsigs)
+    dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
+                                                 "Function Signatures");
+
+  if (opts::pretty::Typedefs)
+    dumpSymbolCategory<PDBSymbolTypeTypedef>(Printer, Exe, *this, "Typedefs");
+
+  if (opts::pretty::Pointers)
+    dumpSymbolCategory<PDBSymbolTypePointer>(Printer, Exe, *this, "Pointers");
 
   if (opts::pretty::Classes) {
     if (auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>()) {
@@ -214,17 +244,11 @@ void TypeDumper::start(const PDBSymbolExe &Exe) {
           if (Printer.IsTypeExcluded(Class->getName(), Class->getLength()))
             continue;
 
+          // No point duplicating a full class layout.  Just print the modified
+          // declaration and continue.
           if (Class->getUnmodifiedTypeId() != 0) {
             Printer.NewLine();
-            if (Class->isConstType())
-              WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
-            if (Class->isVolatileType())
-              WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
-            if (Class->isUnalignedType())
-              WithColor(Printer, PDB_ColorItem::Keyword).get() << "unaligned ";
-            WithColor(Printer, PDB_ColorItem::Keyword).get()
-                << Class->getUdtKind() << " ";
-            WithColor(Printer, PDB_ColorItem::Type).get() << Class->getName();
+            printClassDecl(Printer, *Class);
             continue;
           }
 
@@ -244,34 +268,59 @@ void TypeDumper::start(const PDBSymbolExe &Exe) {
 void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
   assert(opts::pretty::Enums);
 
-  if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
-    return;
-  // Dump member enums when dumping their class definition.
-  if (nullptr != Symbol.getClassParent())
-    return;
-
-  Printer.NewLine();
   EnumDumper Dumper(Printer);
   Dumper.start(Symbol);
 }
 
+void TypeDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+  BuiltinDumper BD(Printer);
+  BD.start(Symbol);
+}
+
 void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
   assert(opts::pretty::Typedefs);
 
-  if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
-    return;
-
-  Printer.NewLine();
   TypedefDumper Dumper(Printer);
   Dumper.start(Symbol);
 }
 
 void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
-  Printer.NewLine();
   FunctionDumper Dumper(Printer);
   Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
 }
 
+void TypeDumper::dump(const PDBSymbolTypePointer &Symbol) {
+  std::unique_ptr<PDBSymbol> P = Symbol.getPointeeType();
+
+  if (auto *FS = dyn_cast<PDBSymbolTypeFunctionSig>(P.get())) {
+    FunctionDumper Dumper(Printer);
+    FunctionDumper::PointerType PT =
+        Symbol.isReference() ? FunctionDumper::PointerType::Reference
+                             : FunctionDumper::PointerType::Pointer;
+    Dumper.start(*FS, nullptr, PT);
+    return;
+  }
+
+  if (auto *UDT = dyn_cast<PDBSymbolTypeUDT>(P.get())) {
+    printClassDecl(Printer, *UDT);
+  } else {
+    P->dump(*this);
+  }
+
+  if (auto Parent = Symbol.getClassParent()) {
+    auto UDT = llvm::unique_dyn_cast<PDBSymbolTypeUDT>(std::move(Parent));
+    if (UDT)
+      Printer << " " << UDT->getName() << "::";
+  }
+
+  if (Symbol.isReference())
+    Printer << "&";
+  else if (Symbol.isRValueReference())
+    Printer << "&&";
+  else
+    Printer << "*";
+}
+
 void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
   assert(opts::pretty::Classes);
 
index b94c4fe..cb6fcb1 100644 (file)
@@ -26,6 +26,8 @@ public:
   void dump(const PDBSymbolTypeEnum &Symbol) override;
   void dump(const PDBSymbolTypeTypedef &Symbol) override;
   void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
+  void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+  void dump(const PDBSymbolTypePointer &Symbol) override;
 
   void dumpClassLayout(const ClassLayout &Class);
 
index 5783661..c9162dd 100644 (file)
@@ -243,6 +243,9 @@ cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
                        cl::cat(TypeCategory), cl::sub(PrettySubcommand));
 cl::opt<bool> Funcsigs("funcsigs", cl::desc("Display function signatures"),
                        cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<bool> Pointers("pointers", cl::desc("Display pointer types"),
+                       cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+
 cl::opt<SymbolSortMode> SymbolOrder(
     "symbol-order", cl::desc("symbol sort order"),
     cl::init(SymbolSortMode::None),
@@ -1179,7 +1182,7 @@ static void dumpPretty(StringRef Path) {
   }
 
   if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs ||
-      opts::pretty::Funcsigs) {
+      opts::pretty::Funcsigs || opts::pretty::Pointers) {
     Printer.NewLine();
     WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
     Printer.Indent();
@@ -1516,6 +1519,8 @@ int main(int Argc, const char **Argv) {
       opts::pretty::Classes = true;
       opts::pretty::Typedefs = true;
       opts::pretty::Enums = true;
+      opts::pretty::Pointers = true;
+      opts::pretty::Funcsigs = true;
     }
 
     // When adding filters for excluded compilands and types, we need to
index 234beb3..eaedb1a 100644 (file)
@@ -84,6 +84,7 @@ extern llvm::cl::opt<bool> Classes;
 extern llvm::cl::opt<bool> Enums;
 extern llvm::cl::opt<bool> Funcsigs;
 extern llvm::cl::opt<bool> Typedefs;
+extern llvm::cl::opt<bool> Pointers;
 extern llvm::cl::opt<bool> All;
 extern llvm::cl::opt<bool> ExcludeCompilerGenerated;