Index: llvm/tools/llvm-pdbdump/LinePrinter.h =================================================================== --- llvm/tools/llvm-pdbdump/LinePrinter.h +++ llvm/tools/llvm-pdbdump/LinePrinter.h @@ -70,6 +70,8 @@ None, Address, Type, + Comment, + Padding, Keyword, Offset, Identifier, Index: llvm/tools/llvm-pdbdump/LinePrinter.cpp =================================================================== --- llvm/tools/llvm-pdbdump/LinePrinter.cpp +++ llvm/tools/llvm-pdbdump/LinePrinter.cpp @@ -99,6 +99,9 @@ case PDB_ColorItem::None: OS.resetColor(); return; + case PDB_ColorItem::Comment: + OS.changeColor(raw_ostream::GREEN, false); + return; case PDB_ColorItem::Address: OS.changeColor(raw_ostream::YELLOW, /*bold=*/true); return; @@ -118,6 +121,7 @@ case PDB_ColorItem::Path: OS.changeColor(raw_ostream::CYAN, false); return; + case PDB_ColorItem::Padding: case PDB_ColorItem::SectionHeader: OS.changeColor(raw_ostream::RED, true); return; Index: llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h +++ llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h @@ -10,6 +10,8 @@ #ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H #define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H +#include "llvm/ADT/BitVector.h" + #include "llvm/DebugInfo/PDB/PDBSymDumper.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" Index: llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp +++ llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp @@ -16,6 +16,8 @@ #include "PrettyVariableDumper.h" #include "llvm-pdbdump.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" @@ -26,6 +28,7 @@ #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/Support/Format.h" using namespace llvm; @@ -34,11 +37,56 @@ ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} +static void analyzePadding(const PDBSymbolTypeUDT &Class, BitVector &Used, + uint32_t &FirstFieldOffset) { + Used.resize(Class.getLength(), true); + auto Children = Class.findAllChildren(); + 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(); + Used.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. + Used.reset(0, FirstFieldOffset); +} + void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { assert(opts::pretty::ClassFormat != opts::pretty::ClassDefinitionFormat::None); - std::string Name = Class.getName(); + uint32_t Size = Class.getLength(); + uint32_t FirstFieldOffset = 0; + BitVector Padding; + analyzePadding(Class, Padding, FirstFieldOffset); + + if (opts::pretty::OnlyPaddingClasses && (Padding.count() == 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(); @@ -66,28 +114,41 @@ auto Children = Class.findAllChildren(); Printer.Indent(); int DumpedCount = 0; - while (auto Child = Children->getNext()) { + bool IsLayoutMode = opts::pretty::ClassFormat == + opts::pretty::ClassDefinitionFormat::LayoutOnly; - if (opts::pretty::ClassFormat == - opts::pretty::ClassDefinitionFormat::LayoutOnly) { - if (auto Data = dyn_cast(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; + uint32_t LayoutFields = 0; + int NextPaddingByte = Padding.find_first(); + while (auto Child = Children->getNext()) { + bool ShowInLayoutMode = false; + + if (auto Data = dyn_cast(Child.get())) { + switch (Data->getLocationType()) { + case PDB_LocType::ThisRel: + case PDB_LocType::BitField: + if (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() + << " (" << Amount << " bytes)"; + assert(Padding.find_next_unset(NextPaddingByte) == Off); + NextPaddingByte = Padding.find_next(Off); + } } - } else { - // Only data symbols affect record layout, so skip any non-data symbols - // if - // we're in record layout mode. - continue; + ++LayoutFields; + ShowInLayoutMode = true; + LLVM_FALLTHROUGH; + default: + break; } } + if (IsLayoutMode && !ShowInLayoutMode) + continue; if (auto Func = dyn_cast(Child.get())) { if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) @@ -102,10 +163,43 @@ Child->dump(*this); } + if (NextPaddingByte >= 0) { + uint32_t Amount = Size - NextPaddingByte; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount + << " bytes)"; + } Printer.Unindent(); if (DumpedCount > 0) Printer.NewLine(); Printer << "}"; + Printer.NewLine(); + if (Padding.count() > 0) { + uint32_t N = 0; + int I = Padding.find_first(); + assert(I != -1); + do { + ++N; + I = Padding.find_next_unset(I); + if (I != -1) + I = Padding.find_next(I); + } while (I != -1); + APFloat OF(100.0 * (double)N / (double)LayoutFields); + SmallString<8> Pct; + OF.toString(Pct, 4); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "Padding occurred " << N << " times (" << Pct << "% incidence)"; + Printer.NewLine(); + + OF = APFloat(100.0 * (double)Padding.count() / + (double)(Size - FirstFieldOffset)); + Pct.clear(); + OF.toString(Pct, 4); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "Total padding " << Padding.count() << " bytes (" << Pct + << "% of class size)"; + Printer.NewLine(); + } } void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {} Index: llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp +++ llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp @@ -98,9 +98,8 @@ if (Printer.IsTypeExcluded(Symbol.getName())) return; - Printer.NewLine(); - if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { + Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); } else { Index: llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp +++ llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp @@ -40,13 +40,15 @@ auto VarType = Var.getType(); + uint64_t Length = VarType->getRawSymbol().getLength(); + switch (auto LocType = Var.getLocationType()) { case PDB_LocType::Static: Printer.NewLine(); Printer << "data ["; WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Var.getVirtualAddress(), 10); - Printer << "] "; + Printer << ", sizeof=" << Length << "] "; WithColor(Printer, PDB_ColorItem::Keyword).get() << "static "; dumpSymbolTypeAndName(*VarType, Var.getName()); break; @@ -54,7 +56,7 @@ if (isa(*VarType)) break; Printer.NewLine(); - Printer << "data "; + Printer << "data [sizeof=" << Length << "] "; WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; dumpSymbolTypeAndName(*VarType, Var.getName()); Printer << " = "; @@ -64,21 +66,23 @@ Printer.NewLine(); Printer << "data "; WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(Var.getOffset(), 4) << " "; + << "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << Length + << "] "; dumpSymbolTypeAndName(*VarType, Var.getName()); break; case PDB_LocType::BitField: Printer.NewLine(); Printer << "data "; WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(Var.getOffset(), 4) << " "; + << "+" << format_hex(Var.getOffset(), 4) << " [sizeof = " << Length + << "] "; dumpSymbolTypeAndName(*VarType, Var.getName()); Printer << " : "; WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength(); break; default: Printer.NewLine(); - Printer << "data "; + Printer << "data [sizeof=" << Length << "] "; Printer << "unknown(" << LocType << ") "; WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName(); break; Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.h =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -36,6 +36,7 @@ extern llvm::cl::list IncludeTypes; extern llvm::cl::list IncludeSymbols; extern llvm::cl::list IncludeCompilands; +extern llvm::cl::opt OnlyPaddingClasses; } namespace raw { Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -122,6 +122,16 @@ cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Typedefs("typedefs", cl::desc("Display typedef types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt 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(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); @@ -161,6 +171,10 @@ "include-compilands", cl::desc("Include only compilands those which match a regular expression"), cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt OnlyPaddingClasses( + "only-padding-classes", cl::desc("When dumping classes, only display those " + "with non-zero amounts of padding bytes"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::opt ExcludeCompilerGenerated( "no-compiler-generated", @@ -170,16 +184,6 @@ ExcludeSystemLibraries("no-system-libs", cl::desc("Don't show symbols from system libraries"), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::opt 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 NoEnumDefs("no-enum-definitions", cl::desc("Don't display full enum definitions"),