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;
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;
};
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)
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);
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();
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();
+}
; 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: }
#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"
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>()) {
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;
}
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);
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);
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),
}
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();
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
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;