diff options
| author | Zachary Turner <zturner@google.com> | 2017-04-12 23:18:21 +0000 |
|---|---|---|
| committer | Zachary Turner <zturner@google.com> | 2017-04-12 23:18:21 +0000 |
| commit | c883a8c6dce207a494c6c3a54de1492635acb664 (patch) | |
| tree | fb2ff9010b62853109fd592e006e560fc2cb4ed7 /llvm/tools | |
| parent | 1b395144442f4bf872fb772c87d8b6e3bf78cfd7 (diff) | |
| download | bcm5719-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.cpp | 131 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h | 6 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp | 2 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp | 34 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp | 2 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp | 23 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/PrettyVariableDumper.h | 1 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp | 21 | ||||
| -rw-r--r-- | llvm/tools/llvm-pdbdump/llvm-pdbdump.h | 2 |
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; |

