summaryrefslogtreecommitdiffstats
path: root/llvm/tools
diff options
context:
space:
mode:
authorZachary Turner <zturner@google.com>2017-04-12 23:18:21 +0000
committerZachary Turner <zturner@google.com>2017-04-12 23:18:21 +0000
commitc883a8c6dce207a494c6c3a54de1492635acb664 (patch)
treefb2ff9010b62853109fd592e006e560fc2cb4ed7 /llvm/tools
parent1b395144442f4bf872fb772c87d8b6e3bf78cfd7 (diff)
downloadbcm5719-llvm-c883a8c6dce207a494c6c3a54de1492635acb664.tar.gz
bcm5719-llvm-c883a8c6dce207a494c6c3a54de1492635acb664.zip
[llvm-pdbdump] More advanced class definition dumping.
Previously the dumping of class definitions was very primitive, and it made it hard to do more than the most trivial of output formats when dumping. As such, we would only dump one line for each field, and then dump non-layout items like nested types and enums. With this patch, we do a complete analysis of the object hierarchy including aggregate types, bases, virtual bases, vftable analysis, etc. The only immediately visible effects of this are that a) we can now dump a line for the vfptr where before we would treat that as padding, and b) we now don't treat virtual bases that come at the end of a class as padding since we have a more detailed analysis of the class's storage usage. In subsequent patches, we should be able to use this analysis to display a complete graphical view of a class's layout including recursing arbitrarily deep into an object's base class / aggregate member hierarchy. llvm-svn: 300133
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp131
-rw-r--r--llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h6
-rw-r--r--llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp2
-rw-r--r--llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp34
-rw-r--r--llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp2
-rw-r--r--llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp23
-rw-r--r--llvm/tools/llvm-pdbdump/PrettyVariableDumper.h1
-rw-r--r--llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp21
-rw-r--r--llvm/tools/llvm-pdbdump/llvm-pdbdump.h2
9 files changed, 119 insertions, 103 deletions
diff --git a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
index b48ed23c1c7..2e1e54e4db1 100644
--- a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
@@ -28,7 +28,8 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
-#include "llvm/Support/Compiler.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
+
#include "llvm/Support/Format.h"
using namespace llvm;
@@ -37,58 +38,23 @@ using namespace llvm::pdb;
ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
: PDBSymDumper(true), Printer(P) {}
-static void analyzePadding(const PDBSymbolTypeUDT &Class, BitVector &Padding,
- uint32_t &FirstFieldOffset) {
- Padding.resize(Class.getLength(), true);
- auto Children = Class.findAllChildren<PDBSymbolData>();
- bool IsFirst = true;
- FirstFieldOffset = Class.getLength();
-
- while (auto Data = Children->getNext()) {
- // Ignore data members which are not relative to this. Usually these are
- // static data members or constexpr and occupy no space. We also need to
- // handle BitFields since the PDB doesn't consider them ThisRel, but they
- // still occupy space in the record layout.
- auto LocType = Data->getLocationType();
- if (LocType != PDB_LocType::ThisRel && LocType != PDB_LocType::BitField)
- continue;
-
- uint64_t Start = Data->getOffset();
- if (IsFirst) {
- FirstFieldOffset = Start;
- IsFirst = false;
- }
-
- auto VarType = Data->getType();
- uint64_t Size = VarType->getRawSymbol().getLength();
- Padding.reset(Start, Start + Size);
- }
-
- // Unmark anything that comes before the first field so it doesn't get
- // counted as padding. In reality this is going to be vptrs or base class
- // members, but we don't correctly handle that yet.
- // FIXME: Handle it.
- Padding.reset(0, FirstFieldOffset);
-}
-
void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
assert(opts::pretty::ClassFormat !=
opts::pretty::ClassDefinitionFormat::None);
uint32_t Size = Class.getLength();
- uint32_t FirstFieldOffset = 0;
- BitVector Padding;
- analyzePadding(Class, Padding, FirstFieldOffset);
- if (opts::pretty::OnlyPaddingClasses && (Padding.count() == 0))
+ ClassLayout Layout(Class.clone());
+
+ if (opts::pretty::OnlyPaddingClasses && (Layout.shallowPaddingSize() == 0))
return;
Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Comment).get() << "// sizeof = " << Size;
- Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
+ WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
+ << "]";
auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>();
if (Bases->getChildCount() > 0) {
@@ -111,60 +77,54 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
}
Printer << " {";
- auto Children = Class.findAllChildren();
Printer.Indent();
- int DumpedCount = 0;
-
- int NextPaddingByte = Padding.find_first();
- while (auto Child = Children->getNext()) {
- if (auto Data = llvm::dyn_cast<PDBSymbolData>(Child.get())) {
- if (Data->getDataKind() == PDB_DataKind::Member && NextPaddingByte >= 0) {
- // If there are padding bytes remaining, see if this field is the first
- // to cross a padding boundary, and print a padding field indicator if
- // so.
- int Off = Data->getOffset();
- if (Off > NextPaddingByte) {
- uint32_t Amount = Off - NextPaddingByte;
- Printer.NewLine();
- WithColor(Printer, PDB_ColorItem::Padding).get()
- << "<padding> (" << Amount << " bytes)";
- assert(Padding.find_next_unset(NextPaddingByte) == Off);
- NextPaddingByte = Padding.find_next(Off);
- }
- }
- }
- if (auto Func = Child->cast<PDBSymbolFunc>()) {
- if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
- continue;
+ // Dump non-layout items first, but only if we're not in layout-only mode.
+ if (opts::pretty::ClassFormat !=
+ opts::pretty::ClassDefinitionFormat::Layout) {
+ for (auto &Other : Layout.other_items())
+ Other->dump(*this);
+ }
- if (Func->getLength() == 0 && !Func->isPureVirtual() &&
- !Func->isIntroVirtualFunction())
- continue;
+ const BitVector &UseMap = Layout.usedBytes();
+ int NextUnusedByte = Layout.usedBytes().find_first_unset();
+ // Next dump items which affect class layout.
+ for (auto &LayoutItem : Layout.layout_items()) {
+ if (NextUnusedByte >= 0) {
+ // If there are padding bytes remaining, see if this field is the first to
+ // cross a padding boundary, and print a padding field indicator if so.
+ int Off = LayoutItem->getOffsetInParent();
+ if (Off > NextUnusedByte) {
+ uint32_t Amount = Off - NextUnusedByte;
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> ("
+ << Amount << " bytes)";
+ assert(UseMap.find_next(NextUnusedByte) == Off);
+ NextUnusedByte = UseMap.find_next_unset(Off);
+ }
}
-
- ++DumpedCount;
- Child->dump(*this);
+ LayoutItem->getSymbol().dump(*this);
}
- if (NextPaddingByte >= 0) {
- uint32_t Amount = Size - NextPaddingByte;
+ if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) {
+ uint32_t Amount = Layout.getClassSize() - NextUnusedByte;
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount
<< " bytes)";
+ DumpedAnything = true;
}
+
Printer.Unindent();
- if (DumpedCount > 0)
+ if (DumpedAnything)
Printer.NewLine();
Printer << "}";
Printer.NewLine();
- if (Padding.count() > 0) {
- APFloat Pct(100.0 * (double)Padding.count() /
- (double)(Size - FirstFieldOffset));
+ if (Layout.deepPaddingSize() > 0) {
+ APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / (double)Size);
SmallString<8> PctStr;
Pct.toString(PctStr, 4);
WithColor(Printer, PDB_ColorItem::Padding).get()
- << "Total padding " << Padding.count() << " bytes (" << PctStr
+ << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr
<< "% of class size)";
Printer.NewLine();
}
@@ -175,23 +135,35 @@ void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
VariableDumper Dumper(Printer);
Dumper.start(Symbol);
+ DumpedAnything = true;
}
void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
if (Printer.IsSymbolExcluded(Symbol.getName()))
return;
+ if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
+ return;
+ if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
+ !Symbol.isIntroVirtualFunction())
+ return;
+ DumpedAnything = true;
Printer.NewLine();
FunctionDumper Dumper(Printer);
Dumper.start(Symbol, FunctionDumper::PointerType::None);
}
-void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
+void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {
+ VariableDumper Dumper(Printer);
+ Dumper.start(Symbol);
+ DumpedAnything = true;
+}
void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
+ DumpedAnything = true;
Printer.NewLine();
EnumDumper Dumper(Printer);
Dumper.start(Symbol);
@@ -201,6 +173,7 @@ void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
+ DumpedAnything = true;
Printer.NewLine();
TypedefDumper Dumper(Printer);
Dumper.start(Symbol);
diff --git a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
index 8f0c35cba81..94ae07d345d 100644
--- a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
+++ b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
@@ -21,6 +21,8 @@
#include <unordered_map>
namespace llvm {
+class BitVector;
+
namespace pdb {
class LinePrinter;
@@ -40,6 +42,10 @@ public:
void dump(const PDBSymbolTypeVTable &Symbol) override;
private:
+ bool maybeDumpSymbol(std::unique_ptr<PDBSymbolData> Data,
+ const BitVector &Padding, int &NextUnusedByte);
+ bool maybeDumpSymbol(std::unique_ptr<PDBSymbolFunc> Data);
+ bool DumpedAnything = false;
LinePrinter &Printer;
};
}
diff --git a/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp
index 0e0da026e56..b0be33c157c 100644
--- a/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp
@@ -233,7 +233,7 @@ void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) {
if (!PointeeType)
return;
- if (auto FuncSig = PointeeType->cast<PDBSymbolTypeFunctionSig>()) {
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
FunctionDumper NestedDumper(Printer);
PointerType Pointer =
Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
diff --git a/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
index 12a47d24f79..2857b07078c 100644
--- a/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp
@@ -26,6 +26,23 @@
using namespace llvm;
using namespace llvm::pdb;
+template <typename Enumerator>
+static std::vector<std::unique_ptr<PDBSymbolTypeUDT>>
+filterClassDefs(LinePrinter &Printer, Enumerator &E) {
+ std::vector<std::unique_ptr<PDBSymbolTypeUDT>> Filtered;
+ while (auto Class = E.getNext()) {
+ if (Class->getUnmodifiedTypeId() != 0)
+ continue;
+
+ if (Printer.IsTypeExcluded(Class->getName()))
+ continue;
+
+ Filtered.push_back(std::move(Class));
+ }
+
+ return Filtered;
+}
+
TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
void TypeDumper::start(const PDBSymbolExe &Exe) {
@@ -53,11 +70,19 @@ void TypeDumper::start(const PDBSymbolExe &Exe) {
if (opts::pretty::Classes) {
auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
+ auto Filtered = filterClassDefs(Printer, *Classes);
+
Printer.NewLine();
+ uint32_t Shown = Filtered.size();
+ uint32_t All = Classes->getChildCount();
+
WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
- Printer << ": (" << Classes->getChildCount() << " items)";
+ Printer << ": (Showing " << Shown << " items";
+ if (Shown < All)
+ Printer << ", " << (All - Shown) << " filtered";
+ Printer << ")";
Printer.Indent();
- while (auto Class = Classes->getNext())
+ for (auto &Class : Filtered)
Class->dump(*this);
Printer.Unindent();
}
@@ -91,11 +116,6 @@ void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
assert(opts::pretty::Classes);
- if (Symbol.getUnmodifiedTypeId() != 0)
- return;
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
diff --git a/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp
index 861f7e28b38..2d8e915d760 100644
--- a/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp
@@ -54,7 +54,7 @@ void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) {
if (Symbol.isVolatileType())
WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
auto PointeeType = Symbol.getPointeeType();
- if (auto FuncSig = PointeeType->cast<PDBSymbolTypeFunctionSig>()) {
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
if (Symbol.isReference())
Pointer = FunctionDumper::PointerType::Reference;
diff --git a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
index 65f0139dfbc..ef9a9b51bd0 100644
--- a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
+++ b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp
@@ -91,6 +91,19 @@ void VariableDumper::start(const PDBSymbolData &Var) {
}
}
+void VariableDumper::start(const PDBSymbolTypeVTable &Var) {
+ Printer.NewLine();
+ Printer << "data ";
+ auto VTableType = cast<PDBSymbolTypePointer>(Var.getType());
+ uint32_t PointerSize = VTableType->getLength();
+
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << PointerSize
+ << "] ";
+
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " __vfptr";
+}
+
void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) {
auto ElementType = Symbol.getElementType();
assert(ElementType);
@@ -157,12 +170,12 @@ void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
if (!PointeeType)
return;
PointeeType->dump(*this);
- if (auto Func = PointeeType->cast<PDBSymbolTypeFunctionSig>()) {
+ if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) {
// A hack to get the calling convention in the right spot.
Printer << " (";
- PDB_CallingConv CC = Func->getCallingConvention();
+ PDB_CallingConv CC = FuncSig->getCallingConvention();
WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
- } else if (isa<PDBSymbolTypeArray>(PointeeType.get())) {
+ } else if (isa<PDBSymbolTypeArray>(PointeeType)) {
Printer << " (";
}
Printer << (Symbol.isReference() ? "&" : "*");
@@ -177,8 +190,8 @@ void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) {
assert(PointeeType);
if (!PointeeType)
return;
- if (isa<PDBSymbolTypeFunctionSig>(PointeeType.get()) ||
- isa<PDBSymbolTypeArray>(PointeeType.get())) {
+ if (isa<PDBSymbolTypeFunctionSig>(PointeeType) ||
+ isa<PDBSymbolTypeArray>(PointeeType)) {
Printer << ")";
}
PointeeType->dumpRight(*this);
diff --git a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h
index eec389b1707..ba9fdb17655 100644
--- a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h
+++ b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h
@@ -25,6 +25,7 @@ public:
VariableDumper(LinePrinter &P);
void start(const PDBSymbolData &Var);
+ void start(const PDBSymbolTypeVTable &Var);
void dump(const PDBSymbolTypeArray &Symbol) override;
void dump(const PDBSymbolTypeBuiltin &Symbol) override;
diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
index 8a749bab98e..a486c8a0730 100644
--- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -96,7 +96,7 @@ cl::SubCommand
"Analyze various aspects of a PDB's structure");
cl::OptionCategory TypeCategory("Symbol Type Options");
-cl::OptionCategory FilterCategory("Filtering Options");
+cl::OptionCategory FilterCategory("Filtering and Sorting Options");
cl::OptionCategory OtherOptions("Other Options");
namespace pretty {
@@ -122,14 +122,17 @@ cl::opt<bool> Enums("enums", cl::desc("Display enum types"),
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
-cl::opt<ClassDefinitionFormat>
- ClassFormat("class-definitions", cl::desc("Class definition format"),
- cl::init(ClassDefinitionFormat::Standard),
- cl::values(clEnumValN(ClassDefinitionFormat::Standard, "full",
- "Display complete class definition"),
- clEnumValN(ClassDefinitionFormat::None, "none",
- "Don't display class definitions")),
- cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<ClassDefinitionFormat> ClassFormat(
+ "class-definitions", cl::desc("Class definition format"),
+ cl::init(ClassDefinitionFormat::Standard),
+ cl::values(
+ clEnumValN(ClassDefinitionFormat::Standard, "full",
+ "Display complete class definition"),
+ clEnumValN(ClassDefinitionFormat::Layout, "layout",
+ "Only display members that contribute to class size."),
+ clEnumValN(ClassDefinitionFormat::None, "none",
+ "Don't display class definitions")),
+ cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
cl::sub(PrettySubcommand));
diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
index a335d30c4cf..c572176f76d 100644
--- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
+++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h
@@ -18,7 +18,7 @@ namespace opts {
namespace pretty {
-enum class ClassDefinitionFormat { None, Standard };
+enum class ClassDefinitionFormat { None, Layout, Standard };
extern llvm::cl::opt<bool> Compilands;
extern llvm::cl::opt<bool> Symbols;
OpenPOWER on IntegriCloud