From 10683346a57eaec13c4d6885ce845e4bc392441f Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Thu, 13 Apr 2017 21:11:00 +0000 Subject: [PATCH] [llvm-pdbdump] Recursively dump class layout. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300258 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../DebugInfo/PDB/ConcreteSymbolEnumerator.h | 10 +- include/llvm/DebugInfo/PDB/PDBSymbolFunc.h | 2 + include/llvm/DebugInfo/PDB/UDTLayout.h | 39 +++- lib/DebugInfo/PDB/PDBSymbol.cpp | 2 + lib/DebugInfo/PDB/PDBSymbolFunc.cpp | 11 + lib/DebugInfo/PDB/UDTLayout.cpp | 220 ++++++++++++++---- .../llvm-pdbdump/Inputs/SimplePaddingTest.cpp | 45 ++++ .../llvm-pdbdump/Inputs/SimplePaddingTest.pdb | Bin 110592 -> 118784 bytes .../simple-padding-graphical.test | 121 ++++++++++ ...-padding.test => simple-padding-text.test} | 2 +- tools/llvm-pdbdump/LinePrinter.cpp | 17 +- tools/llvm-pdbdump/LinePrinter.h | 5 +- .../PrettyClassDefinitionDumper.cpp | 44 ++-- .../PrettyClassDefinitionDumper.h | 3 +- .../PrettyClassLayoutGraphicalDumper.cpp | 135 ++++++++++- .../PrettyClassLayoutGraphicalDumper.h | 21 +- .../PrettyClassLayoutTextDumper.cpp | 8 +- tools/llvm-pdbdump/PrettyTypeDumper.cpp | 124 ++++++++-- tools/llvm-pdbdump/PrettyTypeDumper.h | 4 +- tools/llvm-pdbdump/PrettyVariableDumper.cpp | 20 +- tools/llvm-pdbdump/PrettyVariableDumper.h | 4 +- tools/llvm-pdbdump/llvm-pdbdump.cpp | 26 ++- tools/llvm-pdbdump/llvm-pdbdump.h | 5 +- 23 files changed, 730 insertions(+), 138 deletions(-) create mode 100644 test/tools/llvm-pdbdump/simple-padding-graphical.test rename test/tools/llvm-pdbdump/{simple-padding.test => simple-padding-text.test} (98%) diff --git a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h index 9bf07383156..9713dce362d 100644 --- a/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h +++ b/include/llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h @@ -34,12 +34,11 @@ public: std::unique_ptr getChildAtIndex(uint32_t Index) const override { std::unique_ptr Child = Enumerator->getChildAtIndex(Index); - return make_concrete_child(std::move(Child)); + return unique_dyn_cast_or_null(Child); } std::unique_ptr getNext() override { - std::unique_ptr Child = Enumerator->getNext(); - return make_concrete_child(std::move(Child)); + return unique_dyn_cast_or_null(Enumerator->getNext()); } void reset() override { Enumerator->reset(); } @@ -50,11 +49,6 @@ public: } private: - std::unique_ptr - make_concrete_child(std::unique_ptr Child) const { - ChildType *ConcreteChild = dyn_cast_or_null(Child.release()); - return std::unique_ptr(ConcreteChild); - } std::unique_ptr Enumerator; }; diff --git a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h index 5686f8716a0..c2f02ea6f12 100644 --- a/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h +++ b/include/llvm/DebugInfo/PDB/PDBSymbolFunc.h @@ -27,6 +27,8 @@ public: void dump(PDBSymDumper &Dumper) const override; + bool isDestructor() const; + std::unique_ptr> getArguments() const; DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::Function) diff --git a/include/llvm/DebugInfo/PDB/UDTLayout.h b/include/llvm/DebugInfo/PDB/UDTLayout.h index fca2d43bb3e..e3dcba50bd1 100644 --- a/include/llvm/DebugInfo/PDB/UDTLayout.h +++ b/include/llvm/DebugInfo/PDB/UDTLayout.h @@ -67,6 +67,8 @@ public: virtual uint32_t deepPaddingSize() const; const PDBSymbolData &getDataMember(); + bool hasUDTLayout() const; + const ClassLayout &getUDTLayout() const; private: std::unique_ptr DataMember; @@ -77,13 +79,24 @@ class VTableLayoutItem : public StorageItemBase { public: VTableLayoutItem(const UDTLayoutBase &Parent, std::unique_ptr VTable); + ArrayRef funcs() const { return VTableFuncs; } + + uint32_t getElementSize() const { return ElementSize; } + + void setFunction(uint32_t Index, PDBSymbolFunc &Func) { + VTableFuncs[Index] = &Func; + } private: + uint32_t ElementSize = 0; + std::unique_ptr Shape; std::unique_ptr VTable; - std::vector> VTableFuncs; + std::vector VTableFuncs; }; class UDTLayoutBase { + template using UniquePtrVector = std::vector>; + public: UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, uint32_t Size); @@ -99,26 +112,37 @@ public: return ChildStorage; } - ArrayRef base_classes() const { return BaseClasses; } + VTableLayoutItem *findVTableAtOffset(uint32_t RelativeOffset); - ArrayRef> other_items() const { - return NonStorageItems; + StringRef getUDTName() const { return Name; } + + ArrayRef bases() const { return BaseClasses; } + ArrayRef> vbases() const { + return VirtualBases; } + ArrayRef> funcs() const { return Funcs; } + + ArrayRef> other_items() const { return Other; } + const PDBSymbol &getSymbolBase() const { return SymbolBase; } protected: void initializeChildren(const PDBSymbol &Sym); void addChildToLayout(std::unique_ptr Child); + void addVirtualOverride(PDBSymbolFunc &Func); + void addVirtualIntro(PDBSymbolFunc &Func); const PDBSymbol &SymbolBase; std::string Name; uint32_t SizeOf = 0; BitVector UsedBytes; - std::vector> NonStorageItems; - std::vector> ChildStorage; + UniquePtrVector Other; + UniquePtrVector Funcs; + UniquePtrVector VirtualBases; + UniquePtrVector ChildStorage; std::vector> ChildrenPerByte; std::vector BaseClasses; VTableLayoutItem *VTable = nullptr; @@ -129,6 +153,8 @@ public: explicit ClassLayout(const PDBSymbolTypeUDT &UDT); explicit ClassLayout(std::unique_ptr UDT); + ClassLayout(ClassLayout &&Other) = default; + const PDBSymbolTypeUDT &getClass() const { return UDT; } private: @@ -142,6 +168,7 @@ public: std::unique_ptr Base); const PDBSymbolTypeBaseClass &getBase() const { return *Base; } + bool isVirtualBase() const { return IsVirtualBase; } private: std::unique_ptr Base; diff --git a/lib/DebugInfo/PDB/PDBSymbol.cpp b/lib/DebugInfo/PDB/PDBSymbol.cpp index 14eb6ba8ad8..74010c2dd7d 100644 --- a/lib/DebugInfo/PDB/PDBSymbol.cpp +++ b/lib/DebugInfo/PDB/PDBSymbol.cpp @@ -159,6 +159,8 @@ PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const { std::unique_ptr PDBSymbol::getChildStats(TagStats &Stats) const { std::unique_ptr Result(findAllChildren()); + if (!Result) + return nullptr; Stats.clear(); while (auto Child = Result->getNext()) { ++Stats[Child->getSymTag()]; diff --git a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp index 3c0bd25ed09..0734a1f8314 100644 --- a/lib/DebugInfo/PDB/PDBSymbolFunc.cpp +++ b/lib/DebugInfo/PDB/PDBSymbolFunc.cpp @@ -95,3 +95,14 @@ PDBSymbolFunc::getArguments() const { } void PDBSymbolFunc::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +bool PDBSymbolFunc::isDestructor() const { + std::string Name = getName(); + if (Name.empty()) + return false; + if (Name[0] == '~') + return true; + if (Name == "__vecDelDtor") + return true; + return false; +} diff --git a/lib/DebugInfo/PDB/UDTLayout.cpp b/lib/DebugInfo/PDB/UDTLayout.cpp index 5751e020cb7..61cef093d4c 100644 --- a/lib/DebugInfo/PDB/UDTLayout.cpp +++ b/lib/DebugInfo/PDB/UDTLayout.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBSymbol.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" @@ -70,6 +71,12 @@ const PDBSymbolData &DataMemberLayoutItem::getDataMember() { return *dyn_cast(&Symbol); } +bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; } + +const ClassLayout &DataMemberLayoutItem::getUDTLayout() const { + return *UdtLayout; +} + uint32_t DataMemberLayoutItem::deepPaddingSize() const { uint32_t Result = StorageItemBase::deepPaddingSize(); if (UdtLayout) @@ -81,31 +88,13 @@ VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, std::unique_ptr VTable) : StorageItemBase(Parent, *VTable, "", 0, getTypeLength(*VTable)), VTable(std::move(VTable)) { - // initialize vtbl methods. auto VTableType = cast(this->VTable->getType()); - uint32_t PointerSize = VTableType->getLength(); + ElementSize = VTableType->getLength(); - if (auto Shape = unique_dyn_cast( - VTableType->getPointeeType())) { + Shape = + unique_dyn_cast(VTableType->getPointeeType()); + if (Shape) VTableFuncs.resize(Shape->getCount()); - - auto ParentFunctions = - Parent.getSymbolBase().findAllChildren(); - while (auto Func = ParentFunctions->getNext()) { - if (Func->isVirtual()) { - uint32_t Index = Func->getVirtualBaseOffset(); - assert(Index % PointerSize == 0); - Index /= PointerSize; - - // Don't allow a compiler generated function to overwrite a user - // function in the VTable. Not sure why this happens, but a function - // named __vecDelDtor sometimes shows up on top of the destructor. - if (Func->isCompilerGenerated() && VTableFuncs[Index]) - continue; - VTableFuncs[Index] = std::move(Func); - } - } - } } UDTLayoutBase::UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, @@ -145,44 +134,191 @@ uint32_t UDTLayoutBase::deepPaddingSize() const { } void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { + // Handled bases first, followed by VTables, followed by data members, + // followed by functions, followed by other. This ordering is necessary + // so that bases and vtables get initialized before any functions which + // may override them. + + UniquePtrVector Bases; + UniquePtrVector VTables; + UniquePtrVector Members; auto Children = Sym.findAllChildren(); while (auto Child = Children->getNext()) { - if (auto Data = unique_dyn_cast(Child)) { - if (Data->getDataKind() == PDB_DataKind::Member) { - auto DM = - llvm::make_unique(*this, std::move(Data)); - - addChildToLayout(std::move(DM)); - } else { - NonStorageItems.push_back(std::move(Data)); - } - continue; + if (auto Base = unique_dyn_cast(Child)) { + if (Base->isVirtualBaseClass()) + VirtualBases.push_back(std::move(Base)); + else + Bases.push_back(std::move(Base)); } - if (auto Base = unique_dyn_cast(Child)) { - auto BL = llvm::make_unique(*this, std::move(Base)); - BaseClasses.push_back(BL.get()); + else if (auto Data = unique_dyn_cast(Child)) { + if (Data->getDataKind() == PDB_DataKind::Member) + Members.push_back(std::move(Data)); + else + Other.push_back(std::move(Child)); + } else if (auto VT = unique_dyn_cast(Child)) + VTables.push_back(std::move(VT)); + else if (auto Func = unique_dyn_cast(Child)) + Funcs.push_back(std::move(Func)); + else + Other.push_back(std::move(Child)); + } - addChildToLayout(std::move(BL)); + for (auto &Base : Bases) { + auto BL = llvm::make_unique(*this, std::move(Base)); + BaseClasses.push_back(BL.get()); + + addChildToLayout(std::move(BL)); + } + + for (auto &VT : VTables) { + auto VTLayout = llvm::make_unique(*this, std::move(VT)); + + VTable = VTLayout.get(); + + addChildToLayout(std::move(VTLayout)); + continue; + } + + for (auto &Data : Members) { + auto DM = llvm::make_unique(*this, std::move(Data)); + + addChildToLayout(std::move(DM)); + } + + for (auto &Func : Funcs) { + if (!Func->isVirtual()) continue; - } - if (auto VT = unique_dyn_cast(Child)) { - auto VTLayout = llvm::make_unique(*this, std::move(VT)); + if (Func->isIntroVirtualFunction()) + addVirtualIntro(*Func); + else + addVirtualOverride(*Func); + } +} + +void UDTLayoutBase::addVirtualIntro(PDBSymbolFunc &Func) { + // Kind of a hack, but we prefer the more common destructor name that people + // are familiar with, e.g. ~ClassName. It seems there are always both and + // the vector deleting destructor overwrites the nice destructor, so just + // ignore the vector deleting destructor. + if (Func.getName() == "__vecDelDtor") + return; + + if (!VTable) { + // FIXME: Handle this. What's most likely happening is we have an intro + // virtual in a derived class where the base also has an intro virtual. + // In this case the vtable lives in the base. What we really need is + // for each UDTLayoutBase to contain a list of all its vtables, and + // then propagate this list up the hierarchy so that derived classes have + // direct access to their bases' vtables. + return; + } - VTable = VTLayout.get(); + uint32_t Stride = VTable->getElementSize(); + + uint32_t Index = Func.getVirtualBaseOffset(); + assert(Index % Stride == 0); + Index /= Stride; + + VTable->setFunction(Index, Func); +} - addChildToLayout(std::move(VTLayout)); +VTableLayoutItem *UDTLayoutBase::findVTableAtOffset(uint32_t RelativeOffset) { + if (VTable && VTable->getOffsetInParent() == RelativeOffset) + return VTable; + for (auto Base : BaseClasses) { + uint32_t Begin = Base->getOffsetInParent(); + uint32_t End = Begin + Base->getSize(); + if (RelativeOffset < Begin || RelativeOffset >= End) + continue; + + return Base->findVTableAtOffset(RelativeOffset - Begin); + } + + return nullptr; +} + +void UDTLayoutBase::addVirtualOverride(PDBSymbolFunc &Func) { + auto Signature = Func.getSignature(); + auto ThisAdjust = Signature->getThisAdjust(); + // ThisAdjust tells us which VTable we're looking for. Specifically, it's + // the offset into the current class of the VTable we're looking for. So + // look through the base hierarchy until we find one such that + // AbsoluteOffset(VT) == ThisAdjust + VTableLayoutItem *VT = findVTableAtOffset(ThisAdjust); + if (!VT) { + // FIXME: There really should be a vtable here. If there's not it probably + // means that the vtable is in a virtual base, which we don't yet support. + assert(!VirtualBases.empty()); + return; + } + int32_t OverrideIndex = -1; + // Now we've found the VTable. Func will not have a virtual base offset set, + // so instead we need to compare names and signatures. We iterate each item + // in the VTable. All items should already have non null entries because they + // were initialized by the intro virtual, which was guaranteed to come before. + for (auto ItemAndIndex : enumerate(VT->funcs())) { + auto Item = ItemAndIndex.value(); + assert(Item); + // If the name doesn't match, this isn't an override. Note that it's ok + // for the return type to not match (e.g. co-variant return). + if (Item->getName() != Func.getName()) { + if (Item->isDestructor() && Func.isDestructor()) { + OverrideIndex = ItemAndIndex.index(); + break; + } continue; } + // Now make sure it's the right overload. Get the signature of the existing + // vtable method and make sure it has the same arglist and the same cv-ness. + auto ExistingSig = Item->getSignature(); + if (ExistingSig->isConstType() != Signature->isConstType()) + continue; + if (ExistingSig->isVolatileType() != Signature->isVolatileType()) + continue; - NonStorageItems.push_back(std::move(Child)); + // Now compare arguments. Using the raw bytes of the PDB this would be + // trivial + // because there is an ArgListId and they should be identical. But DIA + // doesn't + // expose this, so the best we can do is iterate each argument and confirm + // that + // each one is identical. + if (ExistingSig->getCount() != Signature->getCount()) + continue; + bool IsMatch = true; + auto ExistingEnumerator = ExistingSig->getArguments(); + auto NewEnumerator = Signature->getArguments(); + for (uint32_t I = 0; I < ExistingEnumerator->getChildCount(); ++I) { + auto ExistingArg = ExistingEnumerator->getNext(); + auto NewArg = NewEnumerator->getNext(); + if (ExistingArg->getSymIndexId() != NewArg->getSymIndexId()) { + IsMatch = false; + break; + } + } + if (!IsMatch) + continue; + + // It's a match! Stick the new function into the VTable. + OverrideIndex = ItemAndIndex.index(); + break; } + if (OverrideIndex == -1) { + // FIXME: This is probably due to one of the other FIXMEs in this file. + return; + } + VT->setFunction(OverrideIndex, Func); } void UDTLayoutBase::addChildToLayout(std::unique_ptr Child) { uint32_t Begin = Child->getOffsetInParent(); uint32_t End = Begin + Child->getSize(); + // Due to the empty base optimization, End might point outside the bounds of + // the parent class. If that happens, just clamp the value. + End = std::min(End, getClassSize()); + UsedBytes.set(Begin, End); while (Begin != End) { ChildrenPerByte[Begin].push_back(Child.get()); diff --git a/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp b/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp index b10839beea2..b52af149533 100644 --- a/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp +++ b/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp @@ -116,6 +116,51 @@ struct SimplePadAggregate { // the presence of X will cause 3 bytes of padding to be injected. } N; +struct SimplePadVtable1 { + static void operator delete(void *ptr, size_t sz) {} + virtual ~SimplePadVtable1() {} + virtual void A1() {} + virtual void B1() {} +} O; + +struct SimplePadVtable2 { + static void operator delete(void *ptr, size_t sz) {} + virtual ~SimplePadVtable2() {} + virtual void X2() {} + virtual void Y2() {} + virtual void Z2() {} +} P; + +struct SimplePadVtable3 { + static void operator delete(void *ptr, size_t sz) {} + virtual ~SimplePadVtable3() {} + virtual void Foo3() {} + virtual void Bar3() {} + virtual void Baz3() {} + virtual void Buzz3() {} +} Q; + +struct SimplePadMultiVTables + : public SimplePadVtable1, + public SimplePadVtable2, + public SimplePadVtable3 { + + ~SimplePadMultiVTables() override {} + static void operator delete(void *ptr, size_t sz) {} + + // SimplePadVtable1 overrides + void A1() override {} + + // SimplePadVtable2 overrides + void Y2() override {} + void Z2() override {} + + // SimplePadVtable3 overrides + void Bar3() override {} + void Baz3() override {} + void Buzz3() override {} +} R; + int main(int argc, char **argv) { return 0; diff --git a/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb b/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb index 44207d601935da652b2b241b81aa334f5c8dc88f..f0bd496c1c8552b007ab1839892b02b9fb2ffeae 100644 GIT binary patch literal 118784 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 CU%xE? diff --git a/test/tools/llvm-pdbdump/simple-padding-graphical.test b/test/tools/llvm-pdbdump/simple-padding-graphical.test new file mode 100644 index 00000000000..aacb0a33045 --- /dev/null +++ b/test/tools/llvm-pdbdump/simple-padding-graphical.test @@ -0,0 +1,121 @@ +; RUN: llvm-pdbdump pretty -classes -class-definitions=graphical \ +; RUN: -include-types=SimplePad %p/Inputs/SimplePaddingTest.pdb > %t + +; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PADDING +; RUN: FileCheck -input-file=%t %s -check-prefix=UNION +; RUN: FileCheck -input-file=%t %s -check-prefix=NESTED_UNION +; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS1 +; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS2 +; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PAD_IN_BASE +; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_IN_DERIVED +; RUN: FileCheck -input-file=%t %s -check-prefix=EMPTY_BASE +; RUN: FileCheck -input-file=%t %s -check-prefix=VFPTR +; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT +; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT2 +; RUN: FileCheck -input-file=%t %s -check-prefix=DEEP_INHERIT +; RUN: FileCheck -input-file=%t %s -check-prefix=AGGREGATE + +; NO_PADDING: struct SimplePadNoPadding [sizeof = 8] { +; NO_PADDING-NEXT: data +0x00 [sizeof=4] int X +; NO_PADDING-NEXT: data +0x04 [sizeof=4] int Y +; NO_PADDING-NEXT: } + +; UNION: struct SimplePadUnion [sizeof = 16] { +; UNION-NEXT: data +0x00 [sizeof=4] int X +; UNION-NEXT: data +0x00 [sizeof=8] __int64 Y +; UNION-NEXT: data +0x00 [sizeof=16] SimplePadUnion:: +; UNION-NEXT: data +0x00 [sizeof=4] int X +; UNION-NEXT: (4 bytes) +; UNION-NEXT: data +0x08 [sizeof=8] __int64 Y +; UNION-NEXT: } + +; NESTED_UNION: struct {{SimplePadUnion::.*}} [sizeof = 16] { +; NESTED_UNION-NEXT: data +0x00 [sizeof=4] int X +; NESTED_UNION-NEXT: (4 bytes) +; NESTED_UNION-NEXT: data +0x08 [sizeof=8] __int64 Y +; NESTED_UNION-NEXT: } + +; PAD_FROM_FIELDS1: struct SimplePadFields1 [sizeof = 4] { +; PAD_FROM_FIELDS1-NEXT: data +0x00 [sizeof=1] char A +; PAD_FROM_FIELDS1-NEXT: data +0x01 [sizeof=1] char B +; PAD_FROM_FIELDS1-NEXT: data +0x02 [sizeof=1] char C +; PAD_FROM_FIELDS1-NEXT: (1 bytes) +; PAD_FROM_FIELDS1-NEXT: } + +; PAD_FROM_FIELDS2: struct SimplePadFields2 [sizeof = 8] { +; PAD_FROM_FIELDS2-NEXT: data +0x00 [sizeof=4] int Y +; PAD_FROM_FIELDS2-NEXT: data +0x04 [sizeof=1] char X +; PAD_FROM_FIELDS2-NEXT: (3 bytes) +; PAD_FROM_FIELDS2-NEXT: } + +; NO_PAD_IN_BASE: struct SimplePadBase [sizeof = 4] { +; NO_PAD_IN_BASE-NEXT: data +0x00 [sizeof=4] int X +; NO_PAD_IN_BASE-NEXT: } + +; PAD_IN_DERIVED: struct SimplePadDerived [sizeof = 16] +; PAD_IN_DERIVED-NEXT: : public SimplePadBase { +; PAD_IN_DERIVED-NEXT: base +0x00 [sizeof=4] SimplePadBase +; PAD_IN_DERIVED-NEXT: data +0x00 [sizeof=4] int X +; PAD_IN_DERIVED-NEXT: (4 bytes) +; PAD_IN_DERIVED-NEXT: data +0x08 [sizeof=8] __int64 Y +; PAD_IN_DERIVED-NEXT: } + +; EMPTY_BASE: struct SimplePadEmpty [sizeof = 8] +; EMPTY_BASE-NEXT: : public SimplePadEmptyBase1 +; EMPTY_BASE-NEXT: , public SimplePadEmptyBase2 { +; EMPTY_BASE-NEXT: base +0x00 [sizeof=1] SimplePadEmptyBase1 +; EMPTY_BASE-NEXT: base +0x01 [sizeof=1] SimplePadEmptyBase2 +; EMPTY_BASE-NEXT: (2 bytes) +; EMPTY_BASE-NEXT: data +0x04 [sizeof=4] int X +; EMPTY_BASE-NEXT: } + +; VFPTR: struct SimplePadVfptr [sizeof = 8] { +; VFPTR-NEXT: vfptr +0x00 [sizeof=4] +; VFPTR-NEXT: [0] &SimplePadVfptr::~SimplePadVfptr +; VFPTR-NEXT: data +0x04 [sizeof=4] int X +; VFPTR-NEXT: } + +; MULTIPLE_INHERIT: struct SimplePadMultiInherit [sizeof = 8] +; MULTIPLE_INHERIT-NEXT: : public NonEmptyBase1 +; MULTIPLE_INHERIT-NEXT: , public NonEmptyBase2 { +; MULTIPLE_INHERIT-NEXT: base +0x00 [sizeof=1] NonEmptyBase1 +; MULTIPLE_INHERIT-NEXT: data +0x00 [sizeof=1] bool X +; MULTIPLE_INHERIT-NEXT: base +0x01 [sizeof=1] NonEmptyBase2 +; MULTIPLE_INHERIT-NEXT: data +0x01 [sizeof=1] bool Y +; MULTIPLE_INHERIT-NEXT: (2 bytes) +; MULTIPLE_INHERIT-NEXT: data +0x04 [sizeof=4] int X +; MULTIPLE_INHERIT-NEXT: } + +; MULTIPLE_INHERIT2: SimplePadMultiInherit2 [sizeof = 16] +; MULTIPLE_INHERIT2-NEXT: : public SimplePadFields1 +; MULTIPLE_INHERIT2-NEXT: , public SimplePadFields2 { +; MULTIPLE_INHERIT2-NEXT: base +0x00 [sizeof=4] SimplePadFields1 +; MULTIPLE_INHERIT2-NEXT: data +0x00 [sizeof=1] char A +; MULTIPLE_INHERIT2-NEXT: data +0x01 [sizeof=1] char B +; MULTIPLE_INHERIT2-NEXT: data +0x02 [sizeof=1] char C +; MULTIPLE_INHERIT2-NEXT: (1 bytes) +; MULTIPLE_INHERIT2-NEXT: base +0x04 [sizeof=8] SimplePadFields2 +; MULTIPLE_INHERIT2-NEXT: data +0x04 [sizeof=4] int Y +; MULTIPLE_INHERIT2-NEXT: data +0x08 [sizeof=1] char X +; MULTIPLE_INHERIT2-NEXT: (3 bytes) +; MULTIPLE_INHERIT2-NEXT: data +0x0c [sizeof=4] int X +; MULTIPLE_INHERIT2-NEXT: } + +; DEEP_INHERIT: struct SimplePadTwoLevelInherit [sizeof = 16] +; DEEP_INHERIT-NEXT: : public OneLevelInherit { +; DEEP_INHERIT-NEXT: base +0x00 [sizeof=4] OneLevelInherit +; DEEP_INHERIT-NEXT: base +0x00 [sizeof=1] NonEmptyBase1 +; DEEP_INHERIT-NEXT: data +0x00 [sizeof=1] bool X +; DEEP_INHERIT-NEXT: (1 bytes) +; DEEP_INHERIT-NEXT: data +0x02 [sizeof=2] short Y +; DEEP_INHERIT-NEXT: (4 bytes) +; DEEP_INHERIT-NEXT: data +0x08 [sizeof=8] __int64 Z +; DEEP_INHERIT-NEXT: } + + +; AGGREGATE: struct SimplePadAggregate [sizeof = 8] { +; AGGREGATE-NEXT: data +0x00 [sizeof=1] NonEmptyBase1 X +; AGGREGATE-NEXT: data +0x00 [sizeof=1] bool X +; AGGREGATE-NEXT: (3 bytes) +; AGGREGATE-NEXT: data +0x04 [sizeof=4] int Y +; AGGREGATE-NEXT: } diff --git a/test/tools/llvm-pdbdump/simple-padding.test b/test/tools/llvm-pdbdump/simple-padding-text.test similarity index 98% rename from test/tools/llvm-pdbdump/simple-padding.test rename to test/tools/llvm-pdbdump/simple-padding-text.test index 8f835f154fa..b33af565f65 100644 --- a/test/tools/llvm-pdbdump/simple-padding.test +++ b/test/tools/llvm-pdbdump/simple-padding-text.test @@ -63,7 +63,7 @@ ; EMPTY_BASE-NEXT: } ; VFPTR: struct SimplePadVfptr [sizeof = 8] { -; VFPTR-NEXT: data +0x00 [sizeof=4] __vfptr +; VFPTR-NEXT: vfptr +0x00 [sizeof=4] ; VFPTR-NEXT: data +0x04 [sizeof=4] int X ; VFPTR-NEXT: } diff --git a/tools/llvm-pdbdump/LinePrinter.cpp b/tools/llvm-pdbdump/LinePrinter.cpp index e5dd66fd9aa..d4a5a8d859e 100644 --- a/tools/llvm-pdbdump/LinePrinter.cpp +++ b/tools/llvm-pdbdump/LinePrinter.cpp @@ -12,6 +12,7 @@ #include "llvm-pdbdump.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" #include "llvm/Support/Regex.h" #include @@ -70,8 +71,20 @@ void LinePrinter::NewLine() { OS.indent(CurrentIndent); } -bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName) { - return IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters); +bool LinePrinter::IsClassExcluded(const ClassLayout &Class) { + if (IsTypeExcluded(Class.getUDTName(), Class.getClassSize())) + return true; + if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold) + return true; + return false; +} + +bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) { + if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters)) + return true; + if (Size < opts::pretty::SizeThreshold) + return true; + return false; } bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) { diff --git a/tools/llvm-pdbdump/LinePrinter.h b/tools/llvm-pdbdump/LinePrinter.h index 8b3d8755ad8..1a922feb1e6 100644 --- a/tools/llvm-pdbdump/LinePrinter.h +++ b/tools/llvm-pdbdump/LinePrinter.h @@ -20,6 +20,8 @@ namespace llvm { namespace pdb { +class ClassLayout; + class LinePrinter { friend class WithColor; @@ -34,7 +36,8 @@ public: raw_ostream &getStream() { return OS; } int getIndentLevel() const { return CurrentIndent; } - bool IsTypeExcluded(llvm::StringRef TypeName); + bool IsClassExcluded(const ClassLayout &Class); + bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size); bool IsSymbolExcluded(llvm::StringRef SymbolName); bool IsCompilandExcluded(llvm::StringRef CompilandName); diff --git a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp index ba829e794ea..9f213a4b4d9 100644 --- a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp +++ b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp @@ -33,15 +33,15 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { opts::pretty::ClassDefinitionFormat::None); ClassLayout Layout(Class); + start(Layout); +} - if (opts::pretty::OnlyPaddingClasses && (Layout.shallowPaddingSize() == 0)) - return; - +void ClassDefinitionDumper::start(const ClassLayout &Layout) { prettyPrintClassIntro(Layout); switch (opts::pretty::ClassFormat) { case opts::pretty::ClassDefinitionFormat::Graphical: { - PrettyClassLayoutGraphicalDumper Dumper(Printer); + PrettyClassLayoutGraphicalDumper Dumper(Printer, 0); DumpedAnything = Dumper.start(Layout); break; } @@ -58,6 +58,20 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { prettyPrintClassOutro(Layout); } +static void printBase(LinePrinter &Printer, const PDBSymbolTypeBaseClass &Base, + uint32_t &CurIndex, uint32_t TotalBaseCount, + bool IsVirtual) { + Printer << " "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess(); + if (IsVirtual) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual"; + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName(); + if (++CurIndex < TotalBaseCount) { + Printer.NewLine(); + Printer << ","; + } +} + void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) { DumpedAnything = false; Printer.NewLine(); @@ -69,24 +83,22 @@ void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) { WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size << "]"; - uint32_t BaseCount = Layout.base_classes().size(); - if (BaseCount > 0) { + uint32_t BaseCount = Layout.bases().size(); + uint32_t VBaseCount = Layout.vbases().size(); + uint32_t TotalBaseCount = BaseCount + VBaseCount; + if (TotalBaseCount > 0) { Printer.Indent(); Printer.NewLine(); Printer << ":"; uint32_t BaseIndex = 0; - for (auto BC : Layout.base_classes()) { + for (auto BC : Layout.bases()) { const auto &Base = BC->getBase(); - Printer << " "; - WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess(); - if (Base.isVirtualBaseClass()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual"; - WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName(); - if (++BaseIndex < BaseCount) { - Printer.NewLine(); - Printer << ","; - } + printBase(Printer, Base, BaseIndex, TotalBaseCount, false); } + for (auto &BC : Layout.vbases()) { + printBase(Printer, *BC, BaseIndex, TotalBaseCount, true); + } + Printer.Unindent(); } diff --git a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h index 6b24c7c8398..0e27733b3cc 100644 --- a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h +++ b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h @@ -32,7 +32,8 @@ class ClassDefinitionDumper : public PDBSymDumper { public: ClassDefinitionDumper(LinePrinter &P); - void start(const PDBSymbolTypeUDT &Exe); + void start(const PDBSymbolTypeUDT &Class); + void start(const ClassLayout &Class); private: void prettyPrintClassIntro(const ClassLayout &Class); diff --git a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp index 13368934ed8..d146ca9d471 100644 --- a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp +++ b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp @@ -9,30 +9,143 @@ #include "PrettyClassLayoutGraphicalDumper.h" +#include "LinePrinter.h" +#include "PrettyClassDefinitionDumper.h" +#include "PrettyVariableDumper.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/Format.h" + using namespace llvm; using namespace llvm::pdb; PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper( - LinePrinter &P) - : PDBSymDumper(true) {} + LinePrinter &P, uint32_t InitialOffset) + : PDBSymDumper(true), Printer(P), ClassOffsetZero(InitialOffset), + CurrentAbsoluteOffset(InitialOffset) {} + +bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) { + const BitVector &UseMap = Layout.usedBytes(); + int NextPaddingByte = UseMap.find_first_unset(); + + for (auto &Item : Layout.layout_items()) { + // Calculate the absolute offset of the first byte of the next field. + uint32_t RelativeOffset = Item->getOffsetInParent(); + CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset; + + // Since there is storage there, it should be set! However, this might + // be an empty base, in which case it could extend outside the bounds of + // the parent class. + if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) { + assert(UseMap.test(RelativeOffset)); + + // If there is any remaining padding in this class, and the offset of the + // new item is after the padding, then we must have just jumped over some + // padding. Print a padding row and then look for where the next block + // of padding begins. + if ((NextPaddingByte >= 0) && + (RelativeOffset > uint32_t(NextPaddingByte))) { + printPaddingRow(RelativeOffset - NextPaddingByte); + NextPaddingByte = UseMap.find_next_unset(RelativeOffset); + } + } -bool PrettyClassLayoutGraphicalDumper::start(const ClassLayout &Layout) { - return false; + CurrentItem = Item.get(); + Item->getSymbol().dump(*this); + } + + if (NextPaddingByte >= 0 && Layout.getClassSize() > 1) { + uint32_t Amount = Layout.getClassSize() - NextPaddingByte; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount + << " bytes)"; + DumpedAnything = true; + } + + return DumpedAnything; +} + +void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) { + if (Amount == 0) + return; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount + << " bytes)"; + DumpedAnything = true; } void PrettyClassLayoutGraphicalDumper::dump( - const PDBSymbolTypeBaseClass &Symbol) {} + const PDBSymbolTypeBaseClass &Symbol) { + assert(CurrentItem != nullptr); -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) {} + Printer.NewLine(); + BaseClassLayout &Layout = static_cast(*CurrentItem); -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) {} + std::string Label = Layout.isVirtualBase() ? "vbase" : "base"; + Printer << Label << " "; -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) {} + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(CurrentAbsoluteOffset, 4) + << " [sizeof=" << Layout.getSize() << "] "; -void PrettyClassLayoutGraphicalDumper::dump( - const PDBSymbolTypeTypedef &Symbol) {} + WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName(); -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {} + Printer.Indent(); + uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); + PrettyClassLayoutGraphicalDumper BaseDumper(Printer, ChildOffsetZero); + BaseDumper.start(Layout); + Printer.Unindent(); + + DumpedAnything = true; +} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) { + assert(CurrentItem != nullptr); + + DataMemberLayoutItem &Layout = + static_cast(*CurrentItem); + + VariableDumper VarDumper(Printer); + VarDumper.start(Symbol, ClassOffsetZero); + + if (Layout.hasUDTLayout()) { + Printer.Indent(); + PrettyClassLayoutGraphicalDumper TypeDumper(Printer, ClassOffsetZero); + TypeDumper.start(Layout.getUDTLayout()); + Printer.Unindent(); + } + + DumpedAnything = true; +} void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) { + assert(CurrentItem != nullptr); + + VTableLayoutItem &Layout = static_cast(*CurrentItem); + + VariableDumper VarDumper(Printer); + VarDumper.start(Symbol, ClassOffsetZero); + + Printer.Indent(); + uint32_t Index = 0; + for (auto &Func : Layout.funcs()) { + Printer.NewLine(); + std::string Name = Func->getName(); + auto ParentClass = + unique_dyn_cast(Func->getClassParent()); + assert(ParentClass); + WithColor(Printer, PDB_ColorItem::Address).get() << " [" << Index << "] "; + WithColor(Printer, PDB_ColorItem::Identifier).get() + << "&" << ParentClass->getName(); + Printer << "::"; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; + ++Index; + } + Printer.Unindent(); + + DumpedAnything = true; } diff --git a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h index 6b35b23a855..7dfb74c4e14 100644 --- a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h +++ b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h @@ -18,22 +18,29 @@ namespace llvm { namespace pdb { -class ClassLayout; +class UDTLayoutBase; +class StorageItemBase; class LinePrinter; class PrettyClassLayoutGraphicalDumper : public PDBSymDumper { public: - explicit PrettyClassLayoutGraphicalDumper(LinePrinter &P); + PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t InitialOffset); - bool start(const ClassLayout &Layout); + bool start(const UDTLayoutBase &Layout); void dump(const PDBSymbolTypeBaseClass &Symbol) override; void dump(const PDBSymbolData &Symbol) override; - void dump(const PDBSymbolTypeEnum &Symbol) override; - void dump(const PDBSymbolFunc &Symbol) override; - void dump(const PDBSymbolTypeTypedef &Symbol) override; - void dump(const PDBSymbolTypeUDT &Symbol) override; void dump(const PDBSymbolTypeVTable &Symbol) override; + +private: + void printPaddingRow(uint32_t Amount); + + LinePrinter &Printer; + + StorageItemBase *CurrentItem = nullptr; + uint32_t ClassOffsetZero = 0; + uint32_t CurrentAbsoluteOffset = 0; + bool DumpedAnything = false; }; } } diff --git a/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp index de654d3f81d..02f31108b0d 100644 --- a/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp +++ b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp @@ -38,6 +38,8 @@ bool PrettyClassLayoutTextDumper::start(const ClassLayout &Layout) { opts::pretty::ClassDefinitionFormat::Standard) { for (auto &Other : Layout.other_items()) Other->dump(*this); + for (auto &Func : Layout.funcs()) + Func->dump(*this); } const BitVector &UseMap = Layout.usedBytes(); @@ -101,9 +103,6 @@ void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeVTable &Symbol) { } void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeEnum &Symbol) { - if (Printer.IsTypeExcluded(Symbol.getName())) - return; - DumpedAnything = true; Printer.NewLine(); EnumDumper Dumper(Printer); @@ -111,9 +110,6 @@ void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeEnum &Symbol) { } void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeTypedef &Symbol) { - if (Printer.IsTypeExcluded(Symbol.getName())) - return; - DumpedAnything = true; Printer.NewLine(); TypedefDumper Dumper(Printer); diff --git a/tools/llvm-pdbdump/PrettyTypeDumper.cpp b/tools/llvm-pdbdump/PrettyTypeDumper.cpp index 2857b07078c..ffeef72150d 100644 --- a/tools/llvm-pdbdump/PrettyTypeDumper.cpp +++ b/tools/llvm-pdbdump/PrettyTypeDumper.cpp @@ -22,24 +22,82 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/FormatVariadic.h" using namespace llvm; using namespace llvm::pdb; +using LayoutPtr = std::unique_ptr; + +typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2); + +static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->getUDTName() < S2->getUDTName(); +} + +static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->getClassSize() < S2->getClassSize(); +} + +static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->deepPaddingSize() < S2->deepPaddingSize(); +} + +static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { + switch (Mode) { + case opts::pretty::ClassSortMode::Name: + return CompareNames; + case opts::pretty::ClassSortMode::Size: + return CompareSizes; + case opts::pretty::ClassSortMode::Padding: + return ComparePadding; + default: + return nullptr; + } +} + template -static std::vector> -filterClassDefs(LinePrinter &Printer, Enumerator &E) { - std::vector> Filtered; +static std::vector> +filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E, + uint32_t UnfilteredCount) { + std::vector> Filtered; + + Filtered.reserve(UnfilteredCount); + CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder); + + uint32_t Examined = 0; + uint32_t Discarded = 0; while (auto Class = E.getNext()) { - if (Class->getUnmodifiedTypeId() != 0) + ++Examined; + if (Examined % 10000 == 0) { + outs() << formatv("Examined {0}/{1} items. {2} items discarded\n", + Examined, UnfilteredCount, Discarded); + outs().flush(); + } + + if (Class->getUnmodifiedTypeId() != 0) { + ++Discarded; continue; + } - if (Printer.IsTypeExcluded(Class->getName())) + if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) { + ++Discarded; continue; + } - Filtered.push_back(std::move(Class)); + auto Layout = llvm::make_unique(std::move(Class)); + if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) { + ++Discarded; + continue; + } + + Filtered.push_back(std::move(Layout)); } + if (Comp) + std::sort(Filtered.begin(), Filtered.end(), Comp); return Filtered; } @@ -70,20 +128,52 @@ void TypeDumper::start(const PDBSymbolExe &Exe) { if (opts::pretty::Classes) { auto Classes = Exe.findAllChildren(); - auto Filtered = filterClassDefs(Printer, *Classes); - - Printer.NewLine(); - uint32_t Shown = Filtered.size(); uint32_t All = Classes->getChildCount(); + Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; + + bool Precompute = false; + Precompute = + (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None); + + // If we're using no sort mode, then we can start getting immediate output + // from the tool by just filtering as we go, rather than processing + // everything up front so that we can sort it. This makes the tool more + // responsive. So only precompute the filtered/sorted set of classes if + // necessary due to the specified options. + std::vector Filtered; + uint32_t Shown = All; + if (Precompute) { + Filtered = filterAndSortClassDefs(Printer, *Classes, All); + + Shown = Filtered.size(); + } + Printer << ": (Showing " << Shown << " items"; if (Shown < All) Printer << ", " << (All - Shown) << " filtered"; Printer << ")"; Printer.Indent(); - for (auto &Class : Filtered) - Class->dump(*this); + + // If we pre-computed, iterate the filtered/sorted list, otherwise iterate + // the DIA enumerator and filter on the fly. + if (Precompute) { + for (auto &Class : Filtered) + dumpClassLayout(*Class); + } else { + while (auto Class = Classes->getNext()) { + if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) + continue; + + auto Layout = llvm::make_unique(std::move(Class)); + if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) + continue; + + dumpClassLayout(*Layout); + } + } + Printer.Unindent(); } } @@ -91,7 +181,7 @@ void TypeDumper::start(const PDBSymbolExe &Exe) { void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { assert(opts::pretty::Enums); - if (Printer.IsTypeExcluded(Symbol.getName())) + if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) return; // Dump member enums when dumping their class definition. if (nullptr != Symbol.getClassParent()) @@ -105,7 +195,7 @@ void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { assert(opts::pretty::Typedefs); - if (Printer.IsTypeExcluded(Symbol.getName())) + if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) return; Printer.NewLine(); @@ -113,15 +203,15 @@ void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { Dumper.start(Symbol); } -void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) { +void TypeDumper::dumpClassLayout(const ClassLayout &Class) { assert(opts::pretty::Classes); 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(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getUDTName(); } else { ClassDefinitionDumper Dumper(Printer); - Dumper.start(Symbol); + Dumper.start(Class); } } diff --git a/tools/llvm-pdbdump/PrettyTypeDumper.h b/tools/llvm-pdbdump/PrettyTypeDumper.h index f9d8304c320..68a2f0246eb 100644 --- a/tools/llvm-pdbdump/PrettyTypeDumper.h +++ b/tools/llvm-pdbdump/PrettyTypeDumper.h @@ -15,6 +15,7 @@ namespace llvm { namespace pdb { class LinePrinter; +class ClassLayout; class TypeDumper : public PDBSymDumper { public: @@ -24,7 +25,8 @@ public: void dump(const PDBSymbolTypeEnum &Symbol) override; void dump(const PDBSymbolTypeTypedef &Symbol) override; - void dump(const PDBSymbolTypeUDT &Symbol) override; + + void dumpClassLayout(const ClassLayout &Class); private: LinePrinter &Printer; diff --git a/tools/llvm-pdbdump/PrettyVariableDumper.cpp b/tools/llvm-pdbdump/PrettyVariableDumper.cpp index ef9a9b51bd0..76a0d23bf87 100644 --- a/tools/llvm-pdbdump/PrettyVariableDumper.cpp +++ b/tools/llvm-pdbdump/PrettyVariableDumper.cpp @@ -35,7 +35,7 @@ using namespace llvm::pdb; VariableDumper::VariableDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} -void VariableDumper::start(const PDBSymbolData &Var) { +void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) { if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) return; if (Printer.IsSymbolExcluded(Var.getName())) @@ -68,16 +68,16 @@ void VariableDumper::start(const PDBSymbolData &Var) { Printer.NewLine(); Printer << "data "; WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << Length - << "] "; + << "+" << format_hex(Offset + 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) << " [sizeof=" << Length - << "] "; + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << Length << "] "; dumpSymbolTypeAndName(*VarType, Var.getName()); Printer << " : "; WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength(); @@ -91,17 +91,15 @@ void VariableDumper::start(const PDBSymbolData &Var) { } } -void VariableDumper::start(const PDBSymbolTypeVTable &Var) { +void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) { Printer.NewLine(); - Printer << "data "; + Printer << "vfptr "; auto VTableType = cast(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"; + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << PointerSize << "] "; } void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) { diff --git a/tools/llvm-pdbdump/PrettyVariableDumper.h b/tools/llvm-pdbdump/PrettyVariableDumper.h index ba9fdb17655..4ba3bc97d85 100644 --- a/tools/llvm-pdbdump/PrettyVariableDumper.h +++ b/tools/llvm-pdbdump/PrettyVariableDumper.h @@ -24,8 +24,8 @@ class VariableDumper : public PDBSymDumper { public: VariableDumper(LinePrinter &P); - void start(const PDBSymbolData &Var); - void start(const PDBSymbolTypeVTable &Var); + void start(const PDBSymbolData &Var, uint32_t Offset = 0); + void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0); void dump(const PDBSymbolTypeArray &Symbol) override; void dump(const PDBSymbolTypeBuiltin &Symbol) override; diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index 6d39871699b..06c2afc0bc7 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -122,15 +122,27 @@ cl::opt Enums("enums", cl::desc("Display enum types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt Typedefs("typedefs", cl::desc("Display typedef types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt ClassOrder( + "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None), + cl::values(clEnumValN(ClassSortMode::None, "none", + "Undefined / no particular sort order"), + clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"), + clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"), + clEnumValN(ClassSortMode::Padding, "padding", + "Sort classes by amount of padding")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + cl::opt ClassFormat( "class-definitions", cl::desc("Class definition format"), cl::init(ClassDefinitionFormat::Standard), cl::values( clEnumValN(ClassDefinitionFormat::Standard, "all-members", "Display all class members including data, constants, " - "typedefs, etc"), + "typedefs, functions, etc"), clEnumValN(ClassDefinitionFormat::Layout, "layout-members", "Only display members that contribute to class size."), + clEnumValN(ClassDefinitionFormat::Graphical, "graphical", + "Display graphical representation of each class's layout."), clEnumValN(ClassDefinitionFormat::None, "none", "Don't display class definitions")), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); @@ -173,10 +185,14 @@ cl::list IncludeCompilands( "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 SizeThreshold( + "min-type-size", cl::desc("Displays only those types which are greater " + "than or equal to the specified size."), + cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt PaddingThreshold( + "min-class-padding", cl::desc("Displays only those classes which have at " + "least the specified amount of padding."), + cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); cl::opt ExcludeCompilerGenerated( "no-compiler-generated", diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h index 36a296087ab..a5429a253df 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/tools/llvm-pdbdump/llvm-pdbdump.h @@ -19,6 +19,7 @@ namespace opts { namespace pretty { enum class ClassDefinitionFormat { None, Layout, Graphical, Standard }; +enum class ClassSortMode { None, Name, Size, Padding }; extern llvm::cl::opt Compilands; extern llvm::cl::opt Symbols; @@ -36,7 +37,9 @@ extern llvm::cl::list ExcludeCompilands; extern llvm::cl::list IncludeTypes; extern llvm::cl::list IncludeSymbols; extern llvm::cl::list IncludeCompilands; -extern llvm::cl::opt OnlyPaddingClasses; +extern llvm::cl::opt ClassOrder; +extern llvm::cl::opt SizeThreshold; +extern llvm::cl::opt PaddingThreshold; extern llvm::cl::opt ClassFormat; } -- 2.50.1