mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[PDB] Better native API support for pointers.
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
This commit is contained in:
parent
aa72b05b81
commit
3ba331bf03
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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: }
|
||||
|
@ -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 <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;
|
||||
|
||||
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<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();
|
||||
}
|
||||
}
|
||||
if (opts::pretty::Enums)
|
||||
dumpSymbolCategory<PDBSymbolTypeEnum>(Printer, Exe, *this, "Enums");
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
if (opts::pretty::Funcsigs)
|
||||
dumpSymbolCategory<PDBSymbolTypeFunctionSig>(Printer, Exe, *this,
|
||||
"Function Signatures");
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user