forked from OSchip/llvm-project
Allow specification of what kinds of class members to dump.
Previously when dumping class definitions, there were only two modes - on or off. But it's useful to sometimes get a little more fine-grained. For example, you might only want to see the record layout (for example to look for extraneous padding). This patch adds a third mode, layout mode, which does exactly that. Only this-relative data members are displayed in this mode. Differential Revision: https://reviews.llvm.org/D31794 llvm-svn: 299733
This commit is contained in:
parent
63230a4e71
commit
10169b6d0d
|
@ -30,7 +30,6 @@
|
|||
|
||||
; TYPES_1: Classes
|
||||
; TYPES_1: struct A {
|
||||
; TYPES_1: public:
|
||||
; TYPES_1: virtual void PureFunc() = 0
|
||||
; TYPES_1: virtual void VirtualFunc()
|
||||
; TYPES_1: void RegularFunc()
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
; MEMBERS_TEST: class MembersTest::A {
|
||||
; MEMBERS_TEST-DAG: typedef int NestedTypedef
|
||||
; MEMBERS_TEST-DAG: enum NestedEnum
|
||||
; MEMBERS_TEST: public:
|
||||
; MEMBERS_TEST-NEXT: void MemberFunc()
|
||||
; MEMBERS_TEST-NEXT: private:
|
||||
; MEMBERS_TEST: void MemberFunc()
|
||||
; MEMBERS_TEST-DAG: int IntMemberVar
|
||||
; MEMBERS_TEST-DAG: double DoubleMemberVar
|
||||
; MEMBERS_TEST: }
|
||||
|
@ -48,7 +46,6 @@
|
|||
|
||||
; BITFIELD_TEST: ---TYPES---
|
||||
; BITFIELD_TEST: struct BitFieldTest::A {
|
||||
; BITFIELD_TEST-NEXT: public:
|
||||
; BITFIELD_TEST-NEXT: +0x00 int Bits1 : 1
|
||||
; BITFIELD_TEST-NEXT: +0x00 int Bits2 : 2
|
||||
; BITFIELD_TEST-NEXT: +0x00 int Bits3 : 3
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
; RUN: llvm-pdbdump pretty -symbols -globals -types %p/Inputs/FilterTest.pdb \
|
||||
; RUN: | FileCheck --check-prefix=NO_FILTER %s
|
||||
|
||||
; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalTypedef|NestedTypedef" \
|
||||
; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_TYPEDEFS %s
|
||||
; RUN: llvm-pdbdump pretty -classes -enums %p/Inputs/FilterTest.pdb \
|
||||
; RUN: | FileCheck --check-prefix=EXCLUDE_TYPEDEFS %s
|
||||
|
||||
; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalEnum|NestedEnum" \
|
||||
; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_ENUMS %s
|
||||
; RUN: llvm-pdbdump pretty -classes -typedefs %p/Inputs/FilterTest.pdb \
|
||||
; RUN: | FileCheck --check-prefix=EXCLUDE_ENUMS %s
|
||||
|
||||
; RUN: llvm-pdbdump pretty -types -symbols -globals -exclude-symbols="MemberVar|GlobalVar" \
|
||||
; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_VARS %s
|
||||
; RUN: llvm-pdbdump pretty -types -exclude-types="FilterTestClass" \
|
||||
|
@ -36,31 +43,25 @@
|
|||
; NO_FILTER-DAG: GlobalEnum GlobalEnumVar
|
||||
|
||||
; EXCLUDE_TYPEDEFS: ---TYPES---
|
||||
; EXCLUDE_TYPEDEFS: Enums:
|
||||
; EXCLUDE_TYPEDEFS: GlobalEnum
|
||||
; EXCLUDE_TYPEDEFS: Typedefs
|
||||
; EXCLUDE_TYPEDEFS-NOT: GlobalTypedef
|
||||
; EXCLUDE_TYPEDEFS: Classes
|
||||
; EXCLUDE_TYPEDEFS: class FilterTestClass
|
||||
; EXCLUDE_TYPEDEFS-NOT: NestedTypedef
|
||||
; EXCLUDE_TYPEDEFS: private:
|
||||
; EXCLUDE_TYPEDEFS-DAG: GlobalEnum
|
||||
; EXCLUDE_TYPEDEFS-DAG: NestedEnum
|
||||
; EXCLUDE_TYPEDEFS: class FilterTestClass
|
||||
|
||||
; EXCLUDE_ENUMS: ---TYPES---
|
||||
; EXCLUDE_ENUMS: Enums:
|
||||
; EXCLUDE_ENUMS-NOT: GlobalEnum
|
||||
; EXCLUDE_ENUMS: Typedefs
|
||||
; EXCLUDE_ENUMS: GlobalTypedef
|
||||
; EXCLUDE_ENUMS: Classes
|
||||
; EXCLUDE_ENUMS: class FilterTestClass
|
||||
; EXCLUDE_ENUMS-NOT: NestedEnum
|
||||
; EXCLUDE_ENUMS: private:
|
||||
; EXCLUDE_ENUMS: GlobalTypedef
|
||||
; EXCLUDE_ENUMS: class FilterTestClass
|
||||
|
||||
; EXCLUDE_VARS: ---TYPES---
|
||||
; EXCLUDE_VARS: Classes:
|
||||
; EXCLUDE_VARS: class FilterTestClass
|
||||
; EXCLUDE_VARS: private:
|
||||
; EXCLUDE_VARS-NOT: IntMemberVar
|
||||
; EXCLUDE_VARS-NOT: DoubleMemberVar
|
||||
; EXCLUDE_VARS-DAG: GlobalEnum
|
||||
; EXCLUDE_VARS-DAG: NestedEnum
|
||||
; EXCLUDE_VARS: GlobalTypedef
|
||||
; EXCLUDE_VARS: class FilterTestClass
|
||||
; EXCLUDE_VARS: ---GLOBALS---
|
||||
; EXCLUDE_VARS-NOT: DoubleGlobalVar
|
||||
; EXCLUDE_VARS-NOT: IntGlobalVar
|
||||
|
|
|
@ -35,6 +35,9 @@ ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
|
|||
: PDBSymDumper(true), Printer(P) {}
|
||||
|
||||
void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
|
||||
assert(opts::pretty::ClassFormat !=
|
||||
opts::pretty::ClassDefinitionFormat::None);
|
||||
|
||||
std::string Name = Class.getName();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
|
||||
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
|
||||
|
@ -61,98 +64,50 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
|
|||
|
||||
Printer << " {";
|
||||
auto Children = Class.findAllChildren();
|
||||
if (Children->getChildCount() == 0) {
|
||||
Printer << "}";
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to dump symbols organized by member access level. Public members
|
||||
// first, then protected, then private. This might be slow, so it's worth
|
||||
// reconsidering the value of this if performance of large PDBs is a problem.
|
||||
// NOTE: Access level of nested types is not recorded in the PDB, so we have
|
||||
// a special case for them.
|
||||
SymbolGroupByAccess Groups;
|
||||
Groups.insert(std::make_pair(0, SymbolGroup()));
|
||||
Groups.insert(std::make_pair((int)PDB_MemberAccess::Private, SymbolGroup()));
|
||||
Groups.insert(
|
||||
std::make_pair((int)PDB_MemberAccess::Protected, SymbolGroup()));
|
||||
Groups.insert(std::make_pair((int)PDB_MemberAccess::Public, SymbolGroup()));
|
||||
|
||||
Printer.Indent();
|
||||
int DumpedCount = 0;
|
||||
while (auto Child = Children->getNext()) {
|
||||
PDB_MemberAccess Access = Child->getRawSymbol().getAccess();
|
||||
if (isa<PDBSymbolTypeBaseClass>(*Child))
|
||||
continue;
|
||||
|
||||
auto &AccessGroup = Groups.find((int)Access)->second;
|
||||
if (opts::pretty::ClassFormat ==
|
||||
opts::pretty::ClassDefinitionFormat::LayoutOnly) {
|
||||
if (auto Data = dyn_cast<PDBSymbolData>(Child.get())) {
|
||||
switch (Data->getLocationType()) {
|
||||
case PDB_LocType::ThisRel:
|
||||
case PDB_LocType::BitField:
|
||||
break;
|
||||
default:
|
||||
// All other types of data field do not occupy any storage (e.g. are
|
||||
// const),
|
||||
// so in layout mode we skip them.
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// Only data symbols affect record layout, so skip any non-data symbols
|
||||
// if
|
||||
// we're in record layout mode.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) {
|
||||
if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
|
||||
continue;
|
||||
|
||||
if (Func->getLength() == 0 && !Func->isPureVirtual() &&
|
||||
!Func->isIntroVirtualFunction())
|
||||
continue;
|
||||
Child.release();
|
||||
AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func));
|
||||
} else if (auto Data = dyn_cast<PDBSymbolData>(Child.get())) {
|
||||
Child.release();
|
||||
AccessGroup.Data.push_back(std::unique_ptr<PDBSymbolData>(Data));
|
||||
} else {
|
||||
AccessGroup.Unknown.push_back(std::move(Child));
|
||||
}
|
||||
|
||||
++DumpedCount;
|
||||
Child->dump(*this);
|
||||
}
|
||||
|
||||
int Count = 0;
|
||||
Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]);
|
||||
Count += dumpAccessGroup(PDB_MemberAccess::Public,
|
||||
Groups[(int)PDB_MemberAccess::Public]);
|
||||
Count += dumpAccessGroup(PDB_MemberAccess::Protected,
|
||||
Groups[(int)PDB_MemberAccess::Protected]);
|
||||
Count += dumpAccessGroup(PDB_MemberAccess::Private,
|
||||
Groups[(int)PDB_MemberAccess::Private]);
|
||||
if (Count > 0)
|
||||
Printer.Unindent();
|
||||
if (DumpedCount > 0)
|
||||
Printer.NewLine();
|
||||
Printer << "}";
|
||||
}
|
||||
|
||||
int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access,
|
||||
const SymbolGroup &Group) {
|
||||
if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty())
|
||||
return 0;
|
||||
|
||||
int Count = 0;
|
||||
if (Access == PDB_MemberAccess::Private) {
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "private";
|
||||
Printer << ":";
|
||||
} else if (Access == PDB_MemberAccess::Protected) {
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "protected";
|
||||
Printer << ":";
|
||||
} else if (Access == PDB_MemberAccess::Public) {
|
||||
Printer.NewLine();
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "public";
|
||||
Printer << ":";
|
||||
}
|
||||
Printer.Indent();
|
||||
for (auto iter = Group.Functions.begin(), end = Group.Functions.end();
|
||||
iter != end; ++iter) {
|
||||
++Count;
|
||||
(*iter)->dump(*this);
|
||||
}
|
||||
for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end;
|
||||
++iter) {
|
||||
++Count;
|
||||
(*iter)->dump(*this);
|
||||
}
|
||||
for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end();
|
||||
iter != end; ++iter) {
|
||||
++Count;
|
||||
(*iter)->dump(*this);
|
||||
}
|
||||
Printer.Unindent();
|
||||
return Count;
|
||||
}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
|
||||
|
||||
void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
|
||||
|
|
|
@ -39,24 +39,6 @@ public:
|
|||
|
||||
private:
|
||||
LinePrinter &Printer;
|
||||
|
||||
struct SymbolGroup {
|
||||
SymbolGroup() {}
|
||||
SymbolGroup(SymbolGroup &&Other) {
|
||||
Functions = std::move(Other.Functions);
|
||||
Data = std::move(Other.Data);
|
||||
Unknown = std::move(Other.Unknown);
|
||||
}
|
||||
|
||||
std::list<std::unique_ptr<PDBSymbolFunc>> Functions;
|
||||
std::list<std::unique_ptr<PDBSymbolData>> Data;
|
||||
std::list<std::unique_ptr<PDBSymbol>> Unknown;
|
||||
SymbolGroup(const SymbolGroup &other) = delete;
|
||||
SymbolGroup &operator=(const SymbolGroup &other) = delete;
|
||||
};
|
||||
typedef std::unordered_map<int, SymbolGroup> SymbolGroupByAccess;
|
||||
|
||||
int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
|
|||
|
||||
Printer.NewLine();
|
||||
|
||||
if (opts::pretty::NoClassDefs) {
|
||||
if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
|
||||
WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
|
||||
WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
|
||||
} else {
|
||||
|
|
|
@ -170,9 +170,17 @@ cl::opt<bool>
|
|||
ExcludeSystemLibraries("no-system-libs",
|
||||
cl::desc("Don't show symbols from system libraries"),
|
||||
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
||||
cl::opt<bool> NoClassDefs("no-class-definitions",
|
||||
cl::desc("Don't display full class definitions"),
|
||||
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
||||
cl::opt<ClassDefinitionFormat> ClassFormat(
|
||||
"class-definitions", cl::desc("Class definition format"),
|
||||
cl::init(ClassDefinitionFormat::Full),
|
||||
cl::values(clEnumValN(ClassDefinitionFormat::Full, "full",
|
||||
"Display complete class definition"),
|
||||
clEnumValN(ClassDefinitionFormat::LayoutOnly, "layout",
|
||||
"Display only members which affect record layout"),
|
||||
clEnumValN(ClassDefinitionFormat::None, "none",
|
||||
"Don't display class definitions")),
|
||||
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
||||
|
||||
cl::opt<bool> NoEnumDefs("no-enum-definitions",
|
||||
cl::desc("Don't display full enum definitions"),
|
||||
cl::cat(FilterCategory), cl::sub(PrettySubcommand));
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
namespace opts {
|
||||
|
||||
namespace pretty {
|
||||
enum class ClassDefinitionFormat { None, LayoutOnly, Full };
|
||||
|
||||
extern llvm::cl::opt<bool> Compilands;
|
||||
extern llvm::cl::opt<bool> Symbols;
|
||||
extern llvm::cl::opt<bool> Globals;
|
||||
|
@ -26,7 +28,7 @@ extern llvm::cl::opt<bool> Typedefs;
|
|||
extern llvm::cl::opt<bool> All;
|
||||
extern llvm::cl::opt<bool> ExcludeCompilerGenerated;
|
||||
|
||||
extern llvm::cl::opt<bool> NoClassDefs;
|
||||
extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
|
||||
extern llvm::cl::opt<bool> NoEnumDefs;
|
||||
extern llvm::cl::list<std::string> ExcludeTypes;
|
||||
extern llvm::cl::list<std::string> ExcludeSymbols;
|
||||
|
|
Loading…
Reference in New Issue