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 @@ -38,7 +38,13 @@ void dump(const PDBSymbolTypeVTable &Symbol) override; private: + void moveToNextField(const PDBSymbolData &Data); LinePrinter &Printer; + + uint64_t TotalPadding = 0; + uint64_t PaddingOccurrences = 0; + uint64_t FieldStart = 0; + uint64_t FieldEnd = 0; }; } } 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; @@ -38,7 +41,11 @@ assert(opts::pretty::ClassFormat != opts::pretty::ClassDefinitionFormat::None); + uint32_t Size = Class.getLength(); std::string Name = Class.getName(); + 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 +73,25 @@ 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; - } - } else { - // Only data symbols affect record layout, so skip any non-data symbols - // if - // we're in record layout mode. - continue; + 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: + moveToNextField(*Data); + ShowInLayoutMode = true; + LLVM_FALLTHROUGH; + default: + break; } } + if (IsLayoutMode && !ShowInLayoutMode) + continue; if (auto Func = dyn_cast(Child.get())) { if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) @@ -106,6 +110,53 @@ if (DumpedCount > 0) Printer.NewLine(); Printer << "}"; + if (PaddingOccurrences > 0 && Class.getLength() > 0) { + APFloat Percent(100.0f * (float)TotalPadding / (float)Class.getLength()); + SmallString<8> FloatStr; + Percent.toString(FloatStr); + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "// Padding: " << TotalPadding << " bytes in " << PaddingOccurrences + << " occurrences. "; + WithColor(Printer, PDB_ColorItem::Padding).get() + << "// " << FloatStr << "% of total class size."; + } + Printer.NewLine(); +} + +void ClassDefinitionDumper::moveToNextField(const PDBSymbolData &Data) { + uint64_t Start = Data.getOffset(); + uint64_t End = Start; + if (Data.getLocationType() == PDB_LocType::ThisRel) { + auto VarType = Data.getType(); + uint64_t Size = VarType->getRawSymbol().getLength(); + End += Size; + } + + if (Start < FieldEnd) { + // If this field starts anywhere in the span of the current field's storage, + // then it must be some kind of union, so we consider it part of the same + // field. In that case, extend the range of this field to cover the new + // field as well. + FieldEnd = std::max(FieldEnd, End); + } else { + // Otherwise, it's a new field. If there is space between the current + // field's end and the new field's start, record padding bytes. Only do + // if we're not at offset 0. That indicates space from the base class or + // vtable, and we don't really want to treat that as padding. In the future + // we should print out information about vtable and virtual base layout to + // make this more clear. + if (Start > FieldEnd && FieldEnd != 0) { + Printer.NewLine(); + auto Padding = Start - FieldEnd; + ++PaddingOccurrences; + TotalPadding += Padding; + WithColor(Printer, PDB_ColorItem::Padding).get() + << " // sizeof = " << Padding; + } + FieldStart = Start; + FieldEnd = End; + } } void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {} 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;