diff --git a/include/llvm/DebugInfo/PDB/Native/NativeTypePointer.h b/include/llvm/DebugInfo/PDB/Native/NativeTypePointer.h index e2f25d19ef6..bcb7431fecf 100644 --- a/include/llvm/DebugInfo/PDB/Native/NativeTypePointer.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeTypePointer.h @@ -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 Record; }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h index 9bc0b1622c9..300d6722fc4 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolTypePointer.h @@ -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) diff --git a/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp b/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp index 4545f7ea769..bd8ecb6c400 100644 --- a/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp +++ b/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp @@ -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(); +} diff --git a/test/DebugInfo/PDB/Native/pdb-native-pointers.test b/test/DebugInfo/PDB/Native/pdb-native-pointers.test index 5bc739b1422..51dc6653f73 100644 --- a/test/DebugInfo/PDB/Native/pdb-native-pointers.test +++ b/test/DebugInfo/PDB/Native/pdb-native-pointers.test @@ -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 @@ -227,10 +260,10 @@ ; 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: } @@ -243,7 +276,7 @@ ; 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: } @@ -256,7 +289,7 @@ ; 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: } diff --git a/tools/llvm-pdbutil/PrettyTypeDumper.cpp b/tools/llvm-pdbutil/PrettyTypeDumper.cpp index 9ffdcfdf956..093164b5068 100644 --- a/tools/llvm-pdbutil/PrettyTypeDumper.cpp +++ b/tools/llvm-pdbutil/PrettyTypeDumper.cpp @@ -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) {} +template +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 +static void dumpSymbolCategory(LinePrinter &Printer, const PDBSymbolExe &Exe, + TypeDumper &TD, StringRef Label) { + if (auto Children = Exe.findAllChildren()) { + 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; + + Printer.NewLine(); + Child->dump(TD); + } + 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) { - if (auto Enums = Exe.findAllChildren()) { - 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(); - } - } + if (opts::pretty::Enums) + dumpSymbolCategory(Printer, Exe, *this, "Enums"); - if (opts::pretty::Funcsigs) { - if (auto Funcsigs = Exe.findAllChildren()) { - 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(); - } - } + if (opts::pretty::Funcsigs) + dumpSymbolCategory(Printer, Exe, *this, + "Function Signatures"); - if (opts::pretty::Typedefs) { - if (auto Typedefs = Exe.findAllChildren()) { - 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(); - } - } + if (opts::pretty::Typedefs) + dumpSymbolCategory(Printer, Exe, *this, "Typedefs"); + + if (opts::pretty::Pointers) + dumpSymbolCategory(Printer, Exe, *this, "Pointers"); if (opts::pretty::Classes) { if (auto Classes = Exe.findAllChildren()) { @@ -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 P = Symbol.getPointeeType(); + + if (auto *FS = dyn_cast(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(P.get())) { + printClassDecl(Printer, *UDT); + } else { + P->dump(*this); + } + + if (auto Parent = Symbol.getClassParent()) { + auto UDT = llvm::unique_dyn_cast(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); diff --git a/tools/llvm-pdbutil/PrettyTypeDumper.h b/tools/llvm-pdbutil/PrettyTypeDumper.h index b94c4feef5f..cb6fcb1add7 100644 --- a/tools/llvm-pdbutil/PrettyTypeDumper.h +++ b/tools/llvm-pdbutil/PrettyTypeDumper.h @@ -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); diff --git a/tools/llvm-pdbutil/llvm-pdbutil.cpp b/tools/llvm-pdbutil/llvm-pdbutil.cpp index 5783661a0b6..c9162dd1577 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -243,6 +243,9 @@ cl::opt Typedefs("typedefs", cl::desc("Display typedef types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Funcsigs("funcsigs", cl::desc("Display function signatures"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Pointers("pointers", cl::desc("Display pointer types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + cl::opt 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 diff --git a/tools/llvm-pdbutil/llvm-pdbutil.h b/tools/llvm-pdbutil/llvm-pdbutil.h index 234beb36e03..eaedb1a56f9 100644 --- a/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/tools/llvm-pdbutil/llvm-pdbutil.h @@ -84,6 +84,7 @@ extern llvm::cl::opt Classes; extern llvm::cl::opt Enums; extern llvm::cl::opt Funcsigs; extern llvm::cl::opt Typedefs; +extern llvm::cl::opt Pointers; extern llvm::cl::opt All; extern llvm::cl::opt ExcludeCompilerGenerated;