From 0e8b7073e9ec0d43329b10e31a9b38d62f51119f Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Mon, 24 Apr 2017 17:47:24 +0000 Subject: [PATCH] [llvm-pdbdump] Re-write the record layout code to be more resilient. This reworks the way virtual bases are handled, and also the way padding is detected across multiple levels of aggregates, producing a much more accurate result. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301203 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h | 3 +- include/llvm/DebugInfo/PDB/IPDBRawSymbol.h | 2 +- .../DebugInfo/PDB/Native/NativeRawSymbol.h | 3 +- include/llvm/DebugInfo/PDB/UDTLayout.h | 140 +++---- lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp | 5 +- lib/DebugInfo/PDB/DIA/DIASession.cpp | 17 +- lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp | 3 +- lib/DebugInfo/PDB/UDTLayout.cpp | 346 ++++++++---------- .../Inputs/ComplexPaddingTest.cpp | 48 +++ .../Inputs/ComplexPaddingTest.pdb | Bin 0 -> 118784 bytes test/tools/llvm-pdbdump/class-layout.test | 5 +- .../complex-padding-graphical.test | 53 +++ .../simple-padding-graphical.test | 9 +- .../llvm-pdbdump/simple-padding-text.test | 94 ----- tools/llvm-pdbdump/LinePrinter.cpp | 2 +- .../PrettyClassDefinitionDumper.cpp | 41 +-- .../PrettyClassLayoutGraphicalDumper.cpp | 57 +-- .../PrettyClassLayoutGraphicalDumper.h | 4 +- .../PrettyClassLayoutTextDumper.cpp | 17 +- .../PrettyClassLayoutTextDumper.h | 1 + tools/llvm-pdbdump/PrettyTypeDumper.cpp | 25 +- tools/llvm-pdbdump/PrettyVariableDumper.cpp | 8 + tools/llvm-pdbdump/PrettyVariableDumper.h | 1 + tools/llvm-pdbdump/llvm-pdbdump.cpp | 15 +- tools/llvm-pdbdump/llvm-pdbdump.h | 2 +- 25 files changed, 451 insertions(+), 450 deletions(-) create mode 100644 test/tools/llvm-pdbdump/Inputs/ComplexPaddingTest.cpp create mode 100644 test/tools/llvm-pdbdump/Inputs/ComplexPaddingTest.pdb create mode 100644 test/tools/llvm-pdbdump/complex-padding-graphical.test delete mode 100644 test/tools/llvm-pdbdump/simple-padding-text.test diff --git a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index c0633cbdfa5..3710eb29e7f 100644 --- a/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -102,7 +102,8 @@ public: uint32_t getVirtualBaseDispIndex() const override; uint32_t getVirtualBaseOffset() const override; uint32_t getVirtualTableShapeId() const override; - std::unique_ptr getVirtualBaseTableType() const override; + std::unique_ptr + getVirtualBaseTableType() const override; PDB_DataKind getDataKind() const override; PDB_SymType getSymTag() const override; PDB_UniqueId getGuid() const override; diff --git a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index 4c28e194bc7..fab086c62c7 100644 --- a/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -113,7 +113,7 @@ public: virtual Variant getValue() const = 0; virtual uint32_t getVirtualBaseDispIndex() const = 0; virtual uint32_t getVirtualBaseOffset() const = 0; - virtual std::unique_ptr + virtual std::unique_ptr getVirtualBaseTableType() const = 0; virtual uint32_t getVirtualTableShapeId() const = 0; virtual PDB_DataKind getDataKind() const = 0; diff --git a/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h index cffb5d09d22..e1e78035ff3 100644 --- a/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h +++ b/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h @@ -101,7 +101,8 @@ public: uint32_t getVirtualBaseDispIndex() const override; uint32_t getVirtualBaseOffset() const override; uint32_t getVirtualTableShapeId() const override; - std::unique_ptr getVirtualBaseTableType() const override; + std::unique_ptr + getVirtualBaseTableType() const override; PDB_DataKind getDataKind() const override; PDB_SymType getSymTag() const override; PDB_UniqueId getGuid() const override; diff --git a/include/llvm/DebugInfo/PDB/UDTLayout.h b/include/llvm/DebugInfo/PDB/UDTLayout.h index e3dcba50bd1..8283113cfe1 100644 --- a/include/llvm/DebugInfo/PDB/UDTLayout.h +++ b/include/llvm/DebugInfo/PDB/UDTLayout.h @@ -15,6 +15,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" #include #include @@ -32,40 +33,62 @@ class PDBSymbolTypeVTable; class ClassLayout; class BaseClassLayout; -class StorageItemBase; +class LayoutItemBase; class UDTLayoutBase; -class StorageItemBase { +class LayoutItemBase { public: - StorageItemBase(const UDTLayoutBase &Parent, const PDBSymbol &Symbol, - const std::string &Name, uint32_t OffsetInParent, - uint32_t Size); - virtual ~StorageItemBase() {} + LayoutItemBase(const UDTLayoutBase *Parent, const PDBSymbol *Symbol, + const std::string &Name, uint32_t OffsetInParent, + uint32_t Size, bool IsElided); + virtual ~LayoutItemBase() {} - virtual uint32_t deepPaddingSize() const; + uint32_t deepPaddingSize() const; + virtual uint32_t tailPadding() const; - const UDTLayoutBase &getParent() const { return Parent; } + const UDTLayoutBase *getParent() const { return Parent; } StringRef getName() const { return Name; } uint32_t getOffsetInParent() const { return OffsetInParent; } uint32_t getSize() const { return SizeOf; } - const PDBSymbol &getSymbol() const { return Symbol; } + uint32_t getLayoutSize() const { return LayoutSize; } + const PDBSymbol *getSymbol() const { return Symbol; } + const BitVector &usedBytes() const { return UsedBytes; } + bool isElided() const { return IsElided; } + virtual bool isVBPtr() const { return false; } + + uint32_t containsOffset(uint32_t Off) const { + uint32_t Begin = getOffsetInParent(); + uint32_t End = Begin + getSize(); + return (Off >= Begin && Off < End); + } protected: - const UDTLayoutBase &Parent; - const PDBSymbol &Symbol; + const PDBSymbol *Symbol = nullptr; + const UDTLayoutBase *Parent = nullptr; BitVector UsedBytes; std::string Name; uint32_t OffsetInParent = 0; uint32_t SizeOf = 0; + uint32_t LayoutSize = 0; + bool IsElided = false; +}; + +class VBPtrLayoutItem : public LayoutItemBase { +public: + VBPtrLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr Sym, uint32_t Offset, + uint32_t Size); + virtual bool isVBPtr() const { return true; } + +private: + std::unique_ptr Type; }; -class DataMemberLayoutItem : public StorageItemBase { +class DataMemberLayoutItem : public LayoutItemBase { public: DataMemberLayoutItem(const UDTLayoutBase &Parent, std::unique_ptr DataMember); - virtual uint32_t deepPaddingSize() const; - const PDBSymbolData &getDataMember(); bool hasUDTLayout() const; const ClassLayout &getUDTLayout() const; @@ -75,77 +98,73 @@ private: std::unique_ptr UdtLayout; }; -class VTableLayoutItem : public StorageItemBase { +class VTableLayoutItem : public LayoutItemBase { 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; }; -class UDTLayoutBase { +class UDTLayoutBase : public LayoutItemBase { template using UniquePtrVector = std::vector>; public: - UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, - uint32_t Size); - - uint32_t shallowPaddingSize() const; - uint32_t deepPaddingSize() const; - - const BitVector &usedBytes() const { return UsedBytes; } + UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym, + const std::string &Name, uint32_t OffsetInParent, uint32_t Size, + bool IsElided); - uint32_t getClassSize() const { return SizeOf; } + uint32_t tailPadding() const override; - ArrayRef> layout_items() const { - return ChildStorage; - } - - VTableLayoutItem *findVTableAtOffset(uint32_t RelativeOffset); + ArrayRef layout_items() const { return LayoutItems; } - StringRef getUDTName() const { return Name; } + ArrayRef bases() const { return AllBases; } + ArrayRef regular_bases() const { return NonVirtualBases; } + ArrayRef virtual_bases() const { return VirtualBases; } - ArrayRef bases() const { return BaseClasses; } - ArrayRef> vbases() const { - return VirtualBases; - } + uint32_t directVirtualBaseCount() const { return DirectVBaseCount; } ArrayRef> funcs() const { return Funcs; } ArrayRef> other_items() const { return Other; } - const PDBSymbol &getSymbolBase() const { return SymbolBase; } - protected: + bool hasVBPtrAtOffset(uint32_t Off) const; void initializeChildren(const PDBSymbol &Sym); - void addChildToLayout(std::unique_ptr Child); - void addVirtualOverride(PDBSymbolFunc &Func); - void addVirtualIntro(PDBSymbolFunc &Func); + void addChildToLayout(std::unique_ptr Child); - const PDBSymbol &SymbolBase; - std::string Name; - uint32_t SizeOf = 0; + uint32_t DirectVBaseCount = 0; - BitVector UsedBytes; UniquePtrVector Other; UniquePtrVector Funcs; - UniquePtrVector VirtualBases; - UniquePtrVector ChildStorage; - std::vector> ChildrenPerByte; - std::vector BaseClasses; + UniquePtrVector ChildStorage; + std::vector LayoutItems; + + std::vector AllBases; + ArrayRef NonVirtualBases; + ArrayRef VirtualBases; + VTableLayoutItem *VTable = nullptr; + VBPtrLayoutItem *VBPtr = nullptr; +}; + +class BaseClassLayout : public UDTLayoutBase { +public: + BaseClassLayout(const UDTLayoutBase &Parent, uint32_t OffsetInParent, + bool Elide, std::unique_ptr Base); + + const PDBSymbolTypeBaseClass &getBase() const { return *Base; } + bool isVirtualBase() const { return IsVirtualBase; } + bool isEmptyBase() { return SizeOf == 1 && LayoutSize == 0; } + +private: + std::unique_ptr Base; + bool IsVirtualBase; }; class ClassLayout : public UDTLayoutBase { @@ -161,19 +180,6 @@ private: std::unique_ptr OwnedStorage; const PDBSymbolTypeUDT &UDT; }; - -class BaseClassLayout : public UDTLayoutBase, public StorageItemBase { -public: - BaseClassLayout(const UDTLayoutBase &Parent, - std::unique_ptr Base); - - const PDBSymbolTypeBaseClass &getBase() const { return *Base; } - bool isVirtualBase() const { return IsVirtualBase; } - -private: - std::unique_ptr Base; - bool IsVirtualBase; -}; } } // namespace llvm diff --git a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp index 5e8c0bdc171..4e2474c51cb 100644 --- a/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp +++ b/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h" #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" @@ -720,7 +721,7 @@ uint32_t DIARawSymbol::getVirtualTableShapeId() const { return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualTableShapeId); } -std::unique_ptr +std::unique_ptr DIARawSymbol::getVirtualBaseTableType() const { CComPtr TableType; if (FAILED(Symbol->get_virtualBaseTableType(&TableType)) || !TableType) @@ -729,7 +730,7 @@ DIARawSymbol::getVirtualBaseTableType() const { auto RawVT = llvm::make_unique(Session, TableType); auto Pointer = llvm::make_unique(Session, std::move(RawVT)); - return unique_dyn_cast(Pointer->getPointeeType()); + return unique_dyn_cast(Pointer->getPointeeType()); } PDB_DataKind DIARawSymbol::getDataKind() const { diff --git a/lib/DebugInfo/PDB/DIA/DIASession.cpp b/lib/DebugInfo/PDB/DIA/DIASession.cpp index 6ecf335812b..ef47b92b4f2 100644 --- a/lib/DebugInfo/PDB/DIA/DIASession.cpp +++ b/lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -21,12 +21,22 @@ #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::pdb; -static Error ErrorFromHResult(HRESULT Result, StringRef Context) { +template +static Error ErrorFromHResult(HRESULT Result, const char *Str, Ts &&... Args) { + SmallString<64> MessageStorage; + StringRef Context; + if (sizeof...(Args) > 0) { + MessageStorage = formatv(Str, std::forward(Args)...).str(); + Context = MessageStorage; + } else + Context = Str; + switch (Result) { case E_PDB_NOT_FOUND: return make_error(generic_error_code::invalid_path, Context); @@ -95,8 +105,9 @@ Error DIASession::createFromPdb(StringRef Path, const wchar_t *Path16Str = reinterpret_cast(Path16.data()); HRESULT HR; - if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) - return ErrorFromHResult(HR, "Calling loadDataFromPdb"); + if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) { + return ErrorFromHResult(HR, "Calling loadDataFromPdb {0}", Path); + } if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) return ErrorFromHResult(HR, "Calling openSession"); diff --git a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp index 3aba35adb53..70968d4330b 100644 --- a/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp +++ b/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" #include "llvm/Support/ConvertUTF.h" @@ -320,7 +321,7 @@ uint32_t NativeRawSymbol::getVirtualTableShapeId() const { return 0; } -std::unique_ptr +std::unique_ptr NativeRawSymbol::getVirtualBaseTableType() const { return nullptr; } diff --git a/lib/DebugInfo/PDB/UDTLayout.cpp b/lib/DebugInfo/PDB/UDTLayout.cpp index 61cef093d4c..6c6bb26ad1b 100644 --- a/lib/DebugInfo/PDB/UDTLayout.cpp +++ b/lib/DebugInfo/PDB/UDTLayout.cpp @@ -16,6 +16,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" @@ -39,36 +40,48 @@ static uint32_t getTypeLength(const PDBSymbol &Symbol) { return RawType.getLength(); } -StorageItemBase::StorageItemBase(const UDTLayoutBase &Parent, - const PDBSymbol &Symbol, - const std::string &Name, - uint32_t OffsetInParent, uint32_t Size) - : Parent(Parent), Symbol(Symbol), Name(Name), - OffsetInParent(OffsetInParent), SizeOf(Size) { +LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent, + const PDBSymbol *Symbol, const std::string &Name, + uint32_t OffsetInParent, uint32_t Size, + bool IsElided) + : Symbol(Symbol), Parent(Parent), Name(Name), + OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size), + IsElided(IsElided) { UsedBytes.resize(SizeOf, true); } -uint32_t StorageItemBase::deepPaddingSize() const { - // sizeof(Field) - sizeof(typeof(Field)) is trailing padding. - return SizeOf - getTypeLength(Symbol); +uint32_t LayoutItemBase::deepPaddingSize() const { + return UsedBytes.size() - UsedBytes.count(); +} + +uint32_t LayoutItemBase::tailPadding() const { + int Last = UsedBytes.find_last(); + + return UsedBytes.size() - (Last + 1); } + DataMemberLayoutItem::DataMemberLayoutItem( - const UDTLayoutBase &Parent, std::unique_ptr DataMember) - : StorageItemBase(Parent, *DataMember, DataMember->getName(), - DataMember->getOffset(), getTypeLength(*DataMember)), - DataMember(std::move(DataMember)) { - auto Type = this->DataMember->getType(); + const UDTLayoutBase &Parent, std::unique_ptr Member) + : LayoutItemBase(&Parent, Member.get(), Member->getName(), + Member->getOffset(), getTypeLength(*Member), false), + DataMember(std::move(Member)) { + auto Type = DataMember->getType(); if (auto UDT = unique_dyn_cast(Type)) { - // UDT data members might have padding in between fields, but otherwise - // a member should occupy its entire storage. - UsedBytes.resize(SizeOf, false); UdtLayout = llvm::make_unique(std::move(UDT)); + UsedBytes = UdtLayout->usedBytes(); } } +VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr Sym, + uint32_t Offset, uint32_t Size) + : LayoutItemBase(&Parent, Sym.get(), "", Offset, Size, false), + Type(std::move(Sym)) { +} + const PDBSymbolData &DataMemberLayoutItem::getDataMember() { - return *dyn_cast(&Symbol); + return *dyn_cast(Symbol); } bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; } @@ -77,36 +90,43 @@ const ClassLayout &DataMemberLayoutItem::getUDTLayout() const { return *UdtLayout; } -uint32_t DataMemberLayoutItem::deepPaddingSize() const { - uint32_t Result = StorageItemBase::deepPaddingSize(); - if (UdtLayout) - Result += UdtLayout->deepPaddingSize(); - return Result; -} - VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, - std::unique_ptr VTable) - : StorageItemBase(Parent, *VTable, "", 0, getTypeLength(*VTable)), - VTable(std::move(VTable)) { - auto VTableType = cast(this->VTable->getType()); + std::unique_ptr VT) + : LayoutItemBase(&Parent, VT.get(), "", 0, getTypeLength(*VT), false), + VTable(std::move(VT)) { + auto VTableType = cast(VTable->getType()); ElementSize = VTableType->getLength(); +} - Shape = - unique_dyn_cast(VTableType->getPointeeType()); - if (Shape) - VTableFuncs.resize(Shape->getCount()); +UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym, + const std::string &Name, uint32_t OffsetInParent, + uint32_t Size, bool IsElided) + : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) { + // UDT storage comes from a union of all the children's storage, so start out + // uninitialized. + UsedBytes.reset(0, Size); + + initializeChildren(Sym); + if (LayoutSize < Size) + UsedBytes.resize(LayoutSize); } -UDTLayoutBase::UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, - uint32_t Size) - : SymbolBase(Symbol), Name(Name), SizeOf(Size) { - UsedBytes.resize(Size); - ChildrenPerByte.resize(Size); - initializeChildren(Symbol); +uint32_t UDTLayoutBase::tailPadding() const { + uint32_t Abs = LayoutItemBase::tailPadding(); + if (!LayoutItems.empty()) { + const LayoutItemBase *Back = LayoutItems.back(); + uint32_t ChildPadding = Back->LayoutItemBase::tailPadding(); + if (Abs < ChildPadding) + Abs = 0; + else + Abs -= ChildPadding; + } + return Abs; } ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT) - : UDTLayoutBase(UDT, UDT.getName(), UDT.getLength()), UDT(UDT) {} + : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false), + UDT(UDT) {} ClassLayout::ClassLayout(std::unique_ptr UDT) : ClassLayout(*UDT) { @@ -114,23 +134,17 @@ ClassLayout::ClassLayout(std::unique_ptr UDT) } BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent, - std::unique_ptr Base) - : UDTLayoutBase(*Base, Base->getName(), Base->getLength()), - StorageItemBase(Parent, *Base, Base->getName(), Base->getOffset(), - Base->getLength()), - Base(std::move(Base)) { - IsVirtualBase = this->Base->isVirtualBaseClass(); -} - -uint32_t UDTLayoutBase::shallowPaddingSize() const { - return UsedBytes.size() - UsedBytes.count(); -} - -uint32_t UDTLayoutBase::deepPaddingSize() const { - uint32_t Result = shallowPaddingSize(); - for (auto &Child : ChildStorage) - Result += Child->deepPaddingSize(); - return Result; + uint32_t OffsetInParent, bool Elide, + std::unique_ptr B) + : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(), + Elide), + Base(std::move(B)) { + if (isEmptyBase()) { + // Special case an empty base so that it doesn't get treated as padding. + UsedBytes.resize(1); + UsedBytes.set(0); + } + IsVirtualBase = Base->isVirtualBaseClass(); } void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { @@ -138,15 +152,16 @@ void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { // 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; + UniquePtrVector VirtualBaseSyms; + auto Children = Sym.findAllChildren(); while (auto Child = Children->getNext()) { if (auto Base = unique_dyn_cast(Child)) { if (Base->isVirtualBaseClass()) - VirtualBases.push_back(std::move(Base)); + VirtualBaseSyms.push_back(std::move(Base)); else Bases.push_back(std::move(Base)); } @@ -164,20 +179,33 @@ void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { Other.push_back(std::move(Child)); } + // We don't want to have any re-allocations in the list of bases, so make + // sure to reserve enough space so that our ArrayRefs don't get invalidated. + AllBases.reserve(Bases.size() + VirtualBaseSyms.size()); + + // Only add non-virtual bases to the class first. Only at the end of the + // class, after all non-virtual bases and data members have been added do we + // add virtual bases. This way the offsets are correctly aligned when we go + // to lay out virtual bases. for (auto &Base : Bases) { - auto BL = llvm::make_unique(*this, std::move(Base)); - BaseClasses.push_back(BL.get()); + uint32_t Offset = Base->getOffset(); + // Non-virtual bases never get elided. + auto BL = llvm::make_unique(*this, Offset, false, + std::move(Base)); + AllBases.push_back(BL.get()); addChildToLayout(std::move(BL)); } + NonVirtualBases = AllBases; - for (auto &VT : VTables) { - auto VTLayout = llvm::make_unique(*this, std::move(VT)); + assert(VTables.size() <= 1); + if (!VTables.empty()) { + auto VTLayout = + llvm::make_unique(*this, std::move(VTables[0])); VTable = VTLayout.get(); addChildToLayout(std::move(VTLayout)); - continue; } for (auto &Data : Members) { @@ -186,150 +214,74 @@ void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { addChildToLayout(std::move(DM)); } - for (auto &Func : Funcs) { - if (!Func->isVirtual()) - continue; + // Make sure add virtual bases before adding functions, since functions may be + // overrides of virtual functions declared in a virtual base, so the VTables + // and virtual intros need to be correctly initialized. + for (auto &VB : VirtualBaseSyms) { + int VBPO = VB->getVirtualBasePointerOffset(); + if (!hasVBPtrAtOffset(VBPO)) { + if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) { + auto VBPL = llvm::make_unique(*this, std::move(VBP), + VBPO, VBP->getLength()); + VBPtr = VBPL.get(); + addChildToLayout(std::move(VBPL)); + } + } - if (Func->isIntroVirtualFunction()) - addVirtualIntro(*Func); - else - addVirtualOverride(*Func); + // Virtual bases always go at the end. So just look for the last place we + // ended when writing something, and put our virtual base there. + // Note that virtual bases get elided unless this is a top-most derived + // class. + uint32_t Offset = UsedBytes.find_last() + 1; + bool Elide = (Parent != nullptr); + auto BL = + llvm::make_unique(*this, Offset, Elide, std::move(VB)); + AllBases.push_back(BL.get()); + + // Only lay this virtual base out directly inside of *this* class if this + // is a top-most derived class. Keep track of it regardless, but only + // physically lay it out if it's a topmost derived class. + addChildToLayout(std::move(BL)); } + VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size()); + + if (Parent != nullptr) + LayoutSize = UsedBytes.find_last() + 1; } -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; +bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const { + if (VBPtr && VBPtr->getOffsetInParent() == Off) + return true; + for (BaseClassLayout *BL : AllBases) { + if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent())) + return true; } - - uint32_t Stride = VTable->getElementSize(); - - uint32_t Index = Func.getVirtualBaseOffset(); - assert(Index % Stride == 0); - Index /= Stride; - - VTable->setFunction(Index, Func); + return false; } -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); - } +void UDTLayoutBase::addChildToLayout(std::unique_ptr Child) { + uint32_t Begin = Child->getOffsetInParent(); - return nullptr; -} + if (!Child->isElided()) { + BitVector ChildBytes = Child->usedBytes(); -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; - - // 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; + // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte + // class. When we call ChildBytes.resize(32), the Child's storage will + // still begin at offset 0, so we need to shift it left by offset bytes + // to get it into the right position. + ChildBytes.resize(UsedBytes.size()); + ChildBytes <<= Child->getOffsetInParent(); + UsedBytes |= ChildBytes; - // 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); -} + if (ChildBytes.count() > 0) { + auto Loc = std::upper_bound(LayoutItems.begin(), LayoutItems.end(), Begin, + [](uint32_t Off, const LayoutItemBase *Item) { + return (Off < Item->getOffsetInParent()); + }); -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()); - ++Begin; + LayoutItems.insert(Loc, Child.get()); + } } - auto Loc = std::upper_bound( - ChildStorage.begin(), ChildStorage.end(), Begin, - [](uint32_t Off, const std::unique_ptr &Item) { - return Off < Item->getOffsetInParent(); - }); - - ChildStorage.insert(Loc, std::move(Child)); + ChildStorage.push_back(std::move(Child)); } \ No newline at end of file diff --git a/test/tools/llvm-pdbdump/Inputs/ComplexPaddingTest.cpp b/test/tools/llvm-pdbdump/Inputs/ComplexPaddingTest.cpp new file mode 100644 index 00000000000..44a4e304ccb --- /dev/null +++ b/test/tools/llvm-pdbdump/Inputs/ComplexPaddingTest.cpp @@ -0,0 +1,48 @@ +// Compile with "cl /c /Zi /GR- ComplexPaddingTest.cpp" +// Link with "link ComplexPaddingTest.obj /debug /nodefaultlib /entry:main" + +#include + +extern "C" using at_exit_handler = void(); + +int atexit(at_exit_handler handler) { return 0; } + +struct TestVB { + static void operator delete(void *ptr, size_t sz) {} + virtual ~TestVB() {} + virtual void IntroFunction1() {} + int X; +} A; + +struct TestNVB { + static void operator delete(void *ptr, size_t sz) {} + virtual ~TestNVB() {} + virtual void IntroFunction2() {} + int Y; +} B; + +struct TestVBLayout + : public virtual TestVB, + public TestNVB { + static void operator delete(void *ptr, size_t sz) {} + int Z; +} C; + +struct TestIVBBase : public virtual TestVB { + int A; +} D; + +struct TestIVBDerived : public TestIVBBase { + int B; +} E; + +struct TestIVBMergedDerived + : public virtual TestVB, + public TestIVBBase { + int B; +} F; + +int main(int argc, char **argv) { + + return 0; +} diff --git a/test/tools/llvm-pdbdump/Inputs/ComplexPaddingTest.pdb b/test/tools/llvm-pdbdump/Inputs/ComplexPaddingTest.pdb new file mode 100644 index 0000000000000000000000000000000000000000..093276bb70816a200b7b7bfe6aa00a3ffc790c22 GIT binary patch literal 118784 zcmeHw4V+v>mG9~9Niz9l5|RKh#3lv^ff;6!kc1IP&tzsuAi+Q;VaN{5bY?n9L(lZs z(-RT|95pDSxIxk9M_9uGii&Gg^Z~1Dz>h^1-UbC1Savt;B8$7aW>EJhF3S7=>sH;a zzJ0sXe66}$m7J-rb57Mcb?Q{zTXpN!U6=05Wrwp{^YK-uuR8VA___@p@#PJTjZ-Jh zY1<$Obs|wj#{+I=8sSY|+CP}m|!g!RwBQqjEN0BC99=}B*64QJ`5JJ9b;Nv?6q>n4&jmmhW$Fo$~IL5MT znHPB$$+%e}qs(T7&eU*zQ>!$rY}x4jOeExmF;jjF@b z+Fi^y6}ZV{_W2@;FM{%!=P2M8jTY)$hqNt6<&Q>Wy3SupE0jG$#?Oesa5KQm_-MpN zFUnxvS;PT6y$aojV-=o@SEX#5}Pq`rl2H|>9Z!w6vWw~R4$p%=HmUSOe&uO z{%Dz|`LETcH8>P2YX@PqO`bAjbF_zkZy?eivGF5iN&eS~=1N0>ey5cCn^jgPz;zil6h zBW=r3`Qalc0MAfL15(qBkIYA!KJpgC^byK4K5`;{7xW60iw3l5#xEWU_{Ch55#|^3 zfM-yCLGyX-B*d5a#$wwyE>XU*0DSZfW~CpTWXUnU!Lq9Hjg!I0P|i0NYI?ypO4}R# zMvYIVtrj8Aq*0O9vg1r!I+yChXtOrCD?5_+$DCrc8h=bXo~HE(`V#TSr^h?s$TGmp`GF@D=Vwgl<0{7ZHIQW^^NY2G;0gfxBZ3>_~+T#}E< z0AH(g^6Fvy@J!&TqtYFk8r@k&kY@BU{@sjxl>Ju3u z1pS%5I2mKzN=+wEU6^)e+$+{g`Qoy&{#@e822te0ExzpH@sN1q!~AXga2wL5?MPb% zpbxhrW}pufZ+!S%{I-2~HPT`E*XaDEG!*L7JRj~rntpVij?YJ2l8?&heC&(V$@uUE z`0eWsO^xm>BS2GC#7ZXo)Go^&dj)>VaanMEw0*W#`)n&{<$QLEcs{!p zJl=Izk4c)eEgMjjxio8ehE#d<;QfrJqfKuWrzEj=jegYh}E& z$j=s+_0Kh%T3eIDDSx2VX?Q2wY9q=w{>R_8|6PoebBU?x>o0bH-2ac^uwLN2mNptaMk$XRp4U?`XPOa*Xeg?I(cRW zwX$5%_Nk6a{RTlg5q#gg2J($>^0)1q??jq*f3@@f84{VzdexwuWInYs zotH6#n*iKEGCjyS!3>!&dk)fYLHN7p>%^U+anmhaLgS9JaGe_WW(&7n<4&}2S8LoU z7H*HmHCVX4z^y}i1pdZ;M_q2$IJ>+rXk3$(_iGyW8C1sP{g%eXqXpbU8uvac?-LsL zjLv(Gj8pb&YwjM-^>t@5I|k|pvV&Rmt2>WTv^$^8W`;e=Q2&SzX_hlMVJ5#XPJR>_h zFqBE{T%YXkPY-TmuWRTV8j>;i@T;y{_l~}%rHu`!u#EkOE~maPUcWgVuRr&q`gr}i z&UpQr`EOvgTRPXS>sZyD9_-7E^rz;(!P1Nvw&`zleJhB(I6c^(y>d8yemXzgeL;I? zN7sh7^ShTeENf^o8h4KjR8qRAgr-J67n;4Xp=s%oGnX_pc8~Ps@~^p&;qA#>s=tb2 zSodjCGaFq}hXdUHg9Tn=(QK1eUSj;U~_l^p6 z=%`SKjtX_?D5^trw&_2?wQ|!h*x!n1SSy{c+wUpWuBm~c{H~sDnd}xUk?WQD7kr+- zufT)h)CFe&X8~scX8~t{Pz&7L&=mRS`D0z2pI<%i&=?6VIG6eE)OpCIe{% zJ3M{ik|4?^yWh?N&H~N?&H~N?&H~N?&H~N?&H~N?&H~N?&H{fx7Qkb0xkw^>3@@+d zS#=f`oDgh$vp zX^=Xl&#$Qz!UO={F&GEneuI5Sb3G!Ww;kY_m3mGGVrh6cUs9MMlc#e}RTO!*CkOi} z18)}K9Rg3zkY35KIV<4_iGJBXv)c`{`>bz!KH zmIdj-bUvNTq_0Zl77%CXY?~TsElX#eKwlhWF!?FFMpgyMe)&|PM%v2K@p=I0?Pcl5 zDtbo=eY~ul&SzB@X!{=GgI$C*fQf)r06s%K;MtcO2a0#9HaC~zkcVx+I+upH-_AVF zvH@l1x2K26M|+>6_2|+ss@Qt)xosR3g+EcI-WcX7V0MjFD|b^sZiklpgqFJj`mp}o zf5KrpRJD;K|=v!@jm+Nb7tTX~Q zAn_;1f9`!q6v_7cni21Jwrb^<>uU!?Ue(-ev?xMXZ;N1GYu3Klrk#o7 zIMsq0YJbOQK^N86lz4VF(qChLyE{ZC_mAu=$Yg(0A}O(2dFA?BBRd%a#}U@?D8M?% zJ7CK*{Y^{No8POJ9qe!CnZB-Nv&(acC)7jsp@QsSe+zDpQ92-7NbttDY5LxU?=BAI zb9h(MyQkp$eZyB3U*Foe!4kpNhx=|07xYo>9aMsC;N=YdedRhl7@`CB_izB#V-VXv zsKV=F2XnpcR4?Hb+kyLt>TDg1Pn2ll`DD-%Ub=dFm@)Zjt;-20fd0wvXmQ_Cyr4_a zM|#x`C2XJ?&gVwB&Fp04skWa4$7ExZZr%(c*m`iE)cS%R{+Jx5K(+FNF94i_`qnA=>b|?A4-Dgl;G}*NIZSpn_h`YsVD5+W zyhtF}`f%^wXhEMsU#O%A%Ba>Cg8jniqAtn-UASNHaFH&Beo;xCYIOXpk{%}D@4 z(1v@CB&+R}%euRatOG}q)&9z5#WAlAtJmQp$?B+H)_L0J_h?zXe9#Yh8K)l(om%XN z-om7HxwJgL8ecT>1o!O>L3w+slc&7@mBg1^&QH?yao_eR2HyJ{CZ6YkuT@Z##_2JZok+`U?^ zJ-_B2{W?!>PfyrZeW+F5rrvyVwl&A^>A_WUAemwP?6qs&XE4~Zx%WT*2Fa#QoU(D9 zA*j;}z{LUHa~QAPk%aB}o~swI3^YoLRs2TYuDFpSx%7BkQj{%w14B$s^pVzUj;tY(dXlM#4@M{ zgIylX@AG-Q z8lTU*rwK0)rttZ^`;qYS-eU22_Y&cJxHS0XdG`U~d>D#-KJOYH&WCZNz^BF=Z#)Rv z1=nbw&l?}Y`QW!cpVyzm+he)K=k>kvd<$XtA*_d857-O13-B=DX~0W>IygZiAOYwF z3<354_5lt64gwAXYT=~E0@ed|0`3Gn3#dWm768@*t_SP~90JV6eETdwH{g1}HvrE9 zroc&70EPhj0FMEFKpi?+8(=5k zF2EtcOc;{)npXpE2RsbmbEcWNcUlVQ0_+Cd1$Yeb5?}$G&4u5O1vu8l0cQbL0C@Hv zV?M$$*P8HaH5goQ7H}4D7H}4D7H}4D7H}4D7H}4D7H}4D7H}5$qp*P9uJ=cwt5ech zz*)dqz*)dqz*)dqz*)dqz*)dqz*)dqz**qcS%A;>ac)0$dEna<@wMr}D^j`mB7Ca} z@9%RzANOW?VOr?>`)k)+a6ah`k+Y{u-JS0px$@%pQI?JBN%)efz z9F3-yj{)eECJeUhMWeQk5hXr^t&ED z4qJmnzYp!>uvN#rv+U!rt;W1-=;OFWF<7432d4I-MSMQ&+cNKU__&3@>HUO0t{yo3 zUW|`h4BP>=SFTVV_C=MH$2}$b-6}tC3vk}P!9v~+;Pg9+J|CS*zn|{o)&uA5l`G`k z2%LV8-sjs4oVVAjz}Ev5_y1ylsL$6AoPLkQ$EAVO?`r$FLE!XzYCdilIDKw_kJ|}c zZ@@0s0H@#2@cG^iTq3~tK9(2I?}H(EZvrmZ9v=hl0QO$lb^8=>jR6_^fYWMV zE@*?#1E_w2s=!b)lb`Y{i^L*K(4Zu-I`zgvJZRpfOzFlxO%8ODS9C9n-pJ+C_vn1gZ}Kg;>Z+^yw`@}~W0cv8Zx4879B9y) zXCp6hqi`QY5|f54!*FcsS;IU-cwbbP-LUGSPV%sR2FG-bkg}j_6*?mGjbpx1yyNHP zYi-D-@NrLay5KC}EZ{8QEZ{8QEZ{8QEbxb50dv30`(Jey!8wR)iZzSl?$O+h^1hY# zuZpL&m@k3*Q*&?0`%2z(hJ^&~H_iPd?&A`QOy#pQxT!ikzwKb&1xe zT|KuI8PoNDM8_BE^1i6)yL3EV$7?j-EFC|i@n6*CUZ>+Rt`u zJ=5CmV;VnB^X=01IZnrCYyQva^esBy89JV-<-r74#ZiCD{P7l>JaKyADekfAs7}Wo z()>jR6KePp3ysY+qy%6TV9}A1Yx&0u2}IrXJQI&qRw<$fVdIB<;K;3PCzdp1K|FN-GDuSy?{FbcLN>7xbIcx$gT`M!#0t)q@`+xB#(U?fu3Wi9H9$h);Yud%z_g-AT#j1WL zgI7UQruUwKuAgGj6%^TYlD4V0Kit&Ol%p#tvay6u)w7h(=y*uCk!r`{FMrt8_I=0O z+pcvC@@sW{KeO9E$Q$qlZ=brUR|vDNqS4#uSM@tGzqg+s<+rijgZxlj`nn+bsgC%3-a8Gt5BPkhI+8H;@!pXz^|2XEb;Pfa z&#USa&TI7a-XSsd@p(;S`gZr;Nh#Dvf5FACk|{4?w-1W*`E->`eY|&itoqoDx=JOy zral#TN7XwMR(*V4Q>DV#;=PYks8i9GVEmdD_1s;NsSngnt1LN$@(t>j^_tz`xvF z1D3TWEIQZ2VzRO&kyx_PaI{!-uAde1tFe^@_~o~G`CCnX#nIyR2awd-TOogNEK<6t z{y<)?(J9^)VdK{F)`WO{2W-*{fZnZ(jo@I>EwY(5BQMwe3OW?Vf@Q6gqcl!{MfG9C zYK^cwKd+Gqb&Vx2*Afdl7s{r#yw;J2^@6UejH(5$7N4gRJO!D4|5gSv<@6dJWgnkM z8OHE{g|ga=ET0RF%DzuJ*F1}4`F&4`Yc+ga7cJDy9wd}VpRW#lklAj@^h<=;R*nx~ zQERM4as&QP>4ukUu|={2ywt$(t_3gTcUbZR+$}O&PEEXGy8xij{ z$!Rim`W#fs>l-b&C#(G3Wb&T^ey=a^+p!*h4ayArj`9rfC&1qedJNxDM&#$I#qY3h zD^o@%@_4?q%I9bQ4ExqH`L~0gAqLHiPDF)$dzt(^i=FhCwEO%s6@Tfsn908f%%1H# ze15!whw@9m%{*Ibr}LXN$$U?0XFA_wzK1;x_z~n8##g9&^85~i*B;%N97Lpa9PmC~ zTin@^9lq`5d)CjVJ>UPLu=l0c22(!P!oBhfe(ker?`65on*V8=zsS4%Tt!&sou~6| zha-5hFxGhN_)(xg;nNM7RJ<3h^RLE%=w5y^a(IQ96nTx^zT@*2+em-1te#%^oJ z8yUXc%-3O+;f&oLwE4813Lla!7|z&jHD2cS?ObG`Larh-bTW2(%+IUr=6^2M&{w0g z7`s@XcJ=Lck3~11CkuRvRTgU-FU2=iy|Ri;6!OVX-)7(O^CioxR{-jQSSf2PZysOcx_ z{3AMjzs~Pd!g#{B26Z(=<+Ys>4+}xyE@-4O}|x__l%Ao(fE6H{RVWs z&eY}9>vE3M=@(5oI&RYXUZ?XT$*{+ZUfExWuH&^00Y3v_v^X6}=m*w_O_=Zfi1X^^ z2UXyxhZyy-!k=h5FC@&5LdJM-lK^uR_`D22DNQZ>s6x~!pZ2^^;@}Do3GZ57LIfV> zE)9u-e$1&WrEKNbrM6HlQwsQk-_-K#8!r|CnY5N)l*zBSMvHls@VJG85L;*7^YA`n z0iY4U`?S@7PCzdp1K_>uZonSEUcjAzy8#CP4+EY6JPSAs;Jx2}*K_>@taGGi`*(q- z()0ZfLf^UQV|&3j3frtle_4P&!o38?0`{ZdKM2~LpzQ>$6EyBYco6xX04>9ONZ*b$ z->c&OfQ8`uHQ=Y4SiWLEi_s2Ryq0ZJ^BsaNolUz-i!N+dYqn z`y3e9KD`8#w-0a#Fr^mz8UQx~4ghK~j+_R_1NH)b3OE*H(R#$Z#y$(4QRF)S;J3zC zAboft$~+Nxz@d}8w44mwDI)Pxfd~Bn@J#Oqe&1WbL%s!YM5IR%3;5RK_d)RNV_Ene z2fi14dlsQfB8~&c->N*6(Fj}}@-feTq{l%{Bj|NHj+2hxqlotb4k7ZNq!d5qS9l?8Vv^3uYCS>piHjys%(B`h#cdo2$y> zS<&RFQO`(y{maOqB@1%$Rpn8iNB4DmwyHep6X$-OPW7DhNV=)dl>2$UQ&k@Isc|vu zvP-duQ0NoITXQ%d8@{`IKGolf82RvKzV6!#a0q4uU#$-N9Jk@wSAl09o~ir;`ZhyU zJ^SGEfZiQj^T{ol)X9+J(YgNN(Y^lfGXTFx^FU?I6I{Itz71OLZksPSX4(aV&jn`zX8~scX8~sc zX8~scXMsOV3mn8Oac)4hFC!fT)DVw3;XKAxu<4v%R?6Rdg#3GsKtFH<`r#wc`Mha@ z)?L*Hzis{b?8wk-HJ?pC0Qwr>Nwf1$)M-Aaszm4Wtqm3O^Ep^0I-jj!O6AMOPo+O~ zrapY`R*BB%X_tbptp0d5Hd&X2NCnp4l+WjEmFNl3F|{nKU+)p$x|*;Xdl_T_WWO7zhq(DxsK&gY)& zzvblfxv8;>(eK~%59Z-BRL&#$+mvDJ&*!m~=zKn0iO%Q3mFRrFySjpWKJ%?a=QHC< zbUqWVfxn3F&k+saC0{2q#oqf(j*HXM&%&-tQ#eOCa z^}2n1FT3UP*R?FFXZDCbhu?8*M=jQUs%#%muF^n0`&)|j_ce@}ykTXLb`XE&B97O2 z_FMG8;ue;y@?mc;=WvGhm%6I3-KK%}pkMARwqw!n=<&WB)xn*B{+T`Pz4&`Wkub%5A z#@0W+?MoD)+93|-=UmXxKKaQBKQT1EmtKyR01f~Bd?!3N^C^?Bw*qYxG*r>g_xOJv z=9YP-%f1S<1E3vk<-6_H{aq&CA<#G_q4b5Jbwje#FoC(awZ&&ssPDo=3jpuL9454w2jbR8dDvbyD+k_hZgV#ouY4D84 zZ51KGi>`qiDsp2qHcHk%ptDEPK;|H!~lcY1JWBtP8UmmL_& zq;?J^`}?sslFSW#Lqqbrpa1UXEO#A?emy^Htm~mw_bSB7y!`THRk@d6o`%?~ko)T_ z;4I)Q;4JV*VF7c^IEELF*YjfZs>&M5rTSA_(}Su0c;Bg~#*_JcF1=+07r6LBUh~o! zY+Fwc=2N-BWabnsQgk-P7o@ff#m`2R9*Q%)G=6IQGKB!12rn`0C02lXc3fp_$R#(V zlDWR^cJ3l(76oRkf~Y_X?FamumsFQoKC0ubvkT4w&H~N?&H~N?&H~N?&H~N?&H~N? z&H~N?f6x}-8u~SL_&yq7^7x31B4(H*kvifd^1|38iPpUvzZZ=v{0vTn--GlVnOGOh zzgy=or6H3~8$Tn4Lf(ZmeXZt92@*tJmvtv;m%AnWrpl0)#*X%2|BQ$v0U9= zV@%(SbiqENeEO5Xg{lu9VgF$nUMZr|EThIR#ltm%qgMJ;ec2q&PmnR%bArr>eoEzK ze)iWl#-6RdPo-M%ye^d-6y@s?N#T5g)V5U4OGhQuk;x|W>~r+Hn55dWBREa~_53h= zuSWacEzr3{)9tCuP%2l{J$5wpBr|zhw{qtQ;Y*Yh7t&d7sLm%#ifV2Sk*J(B1YeaV zp3i<7cCmf-&yY5LN!mUDefCzw4CiPcB%kp?jFm#%l5!Ut|4a@S)pud8E|5 z+Ln2Z^?xC1#@1BJ;I56s7((^fm0Fcul}Qc{7jW>iRc~8I*UN29_N6?6_POz%Pg(@e z7i%T8E;X1z0 zUkkE@>AFabrnM#WNlQnmO<5Mv<$?z0oImDxFHV&qS;)4a$7JD+Gm40xyd7_He(*N(OTXN1o_cE>vOz$$ZH3(M;~ zx;{5xOq{33#5>Rjs~HnV*fXr*P^Ha%luv#2!cOW_)?{7ME>Bl%o1qwg=r$(C$> zyNvCC?~K#Fa~JAU;yd~6xm1!{XMBU;#?s)7!&r!f|J%*RqQk|ca7N(3=iVl-O zU-%2u$-WkT5ozNWqISgx-X%)&XyS8bec z4bPv*kE^TlC)%P0*U!5Zj`&c2@{2DN#T(jEbeJuyIR|bbbNZT?%w)1xsyPOIBr3_w zmC0Sh^dEc9@pb4`;upzn+j1DX)G<%KLZNexP|h$NtGu@lEl;^cC?!M^>PO$W2lcXj z4Ab6-Wj_$Jb!s_OfA@|$}r+JwIG zR|-dbsBeT9NB0P&gxiE;K^61NT&gdHS!=Fxt9uib65bHWV}sR=1!YQ9EnkKfB2Bmb z{jew7ewsvPa58xS=|;q+jY)q1FgY5PZzE>FI*(eXK)3Bz382HR8+kSiCcndGkQNFE=L97+xL^Ae%#JRZLE zeZ|i_yl*P$+2uqPX3y2MD(t-3zfSdM%ykF%bvrqa<9HL3;Z$x%y3eF*WMmMl4SngY zX=_Ys?`rq?H?&{0Y0WC8x58J)>+9CvpgtwF7*MyNm3=h86XGpnmsRJRfs&L@25=#z zYhQc>`s;D1ZU}8+))D`f_)(4{kr{li{9&XITEO+7MgVdAZDXv7fMy z9!1Px{F>#L@mMLZzkW=|k0ag^@vf09-}dVtAssN1@@Mkd{!IOA zuvRvJdl~vS)3t&TXc!X&J!TR&MMg%_{T>f(P$!u_lWs(MCf3&m^SLa2(Ufzna9WOo zU2%uQ>mKpUJJ-T9S88Wo=|(wmi$>2jWi3$nt=M^0&|#s%nG(G6smp1yJ>8FPX=D;t zFF77Do9@fQ{k1NX*C>4>!+9(XTDYa;RSSMS$}sfPqtUnj4*VvpIAX7OC4TCSeX$yj znYC&yo1Xe4TVs z0+SzVitwF0-t+z=V9LpSkMiZ0aZ7~1yz9lgfQSen%k>@#Z_q_>@}7O4gajD;`=rsr zJ$Mv&-cRu!l=oLL%{K%goC}!wD(T~jc%w2N>G3R8HmdcFTINNbMWJ&TK3&H*J2|WK zekS;A+LX`xJg#|~dwxEv_kwqi$KTYSc;4sPd{cp&Oa`5Y`yRGEhVNk>J8>r7 zTSR&~b^uI4Z1xu5n0tJ6AqD)=GEMXA?{)e(6e~psus0Rv2Q|{A)(U4LuWk{wS7Ej# z!|Y#R`PJ-SI9BU{IdRec1^U4x>|Z!e)9D|zMryzh%KHq?Z}*)Bzu`5eecq(Y<!u^ zV|;^URpT2cgO8z{Z!FaGf^U?zH~TZkAJbNgkY~~;*D1pGW>E9u^Zb4HDMqXD$F$>V zT92SF5$~;)MC?{!CxwUaggyPM*3j?aa7Wte5h|Wo7-@d~?G0WP>R3;TB(Z@pwqQ@nQb9 zeYg#2({`k-0?>!s5i`(-i8nrcE`HlSyc+4S{A+anQW^^NX`T;vAWc6yPsisYF3Cq_ zbUykpbuvDD0e<_sLsO$W%LvkpUdD&thP;%$9 z%K7XR?Xzpa<6U>XuY+)njr$AN0k5y)n&9m#ywEDs_$qm;@zsmK#}M>Y`q>ot>IO~c z*n4cTR>n(<{A_Vq|J2_w@!eCW;hk)&jVRyvAAj5acQMkYtx4Mip#OCtW}yEOZ~SjF ze%t={CrF3o@7DQCX(-gEdH#0^()58#b$l7(l6+JKcr%7lC*yxf{PuN+rbc&`5u_Qt zjQ?#xUdrx6TuvrMD;j*$mSe`yKMxs03u9%A8Y_EHKK;(L6n(B2IOTH&318&%!hYb5 z9~+-b0auOBZ3Q1g(C6qoycgW2>E!XoM0)tCv9FE5Jah)3XW(&7n<4&}2S8E(j1@!ao(YOW+w--2` zk2`|(CL{NDjkC-9g2pvjdB3J{pFw3z-fwAK9P@XBdr0HnXXSlD5Ubg{1o0c{-H8w0hgKS&UgWapM!}+ddOS@5McVDK# z+vh&d$o7sQUhf@4%xk+khL~pxyz07j@91k<+Sq^tk7evXbUF2X@%qi_c>TE-)yM1C zb;j%0%zp!`-O{;sUB@aMwcM8(=}*mngQXcUY}4Q9`c@EmaeA;nd*yKa{4|b%zM#Fc zqiaLk`Q1w!mNhgPjk`w%Dk)u5LQ|uk3(elx(6n^PnM)cPyGQzR`PW>?@b)B*^Q@v6 z)_t1P%;plKY{Xto%j)^st9oU6P}Q|_eZ0O)oe?p6oYX<`bO2Z2xci2y z(Hys;vpG**26zV#*|>&dUUc?Gr1?C@#&Ip1Ywb3UWAJ+eI6mv++KtV}H9<|ufTJ#4|F-$4%k=>qb>W^1n~%Co3*e{=pAQ&fG@4-t*-XSV4j2XGSFAd@;m(K};c*^}y2%fg$ewH9V?Zh?EAf9?&6u{5X*X9WD zD_8dPw6`P@m$Ye;3aLZH)eXWk1w z&)-+z!Eow=vw*XJvw*XJvp}c?b}xv@p&ZWdS{{{o4@BjHvtyFIBqG;h!~f885jpz4 znEWFq|3BS?T?u$o{PK3(&)gG{uYmT<X8o1=2m2cmMrnGxCeUlI8vaPQm@ zm8-sm`@xGMa{bRDviUa=**7e5>sKQ(@f#vb*Ttmyx~N?9&4^t5mZ*IC8xh%aFedkP z#$@bsF}ZGy$QOPUlb<{km3KqdOJ9u1O*i8-hYv*Lzrfe`ZIR8hBl4?wOfJpFr0ck- zbRQR!YtDcM|05<>el;d<{uK0n3i}rCkH~XxkI2HOWAgET ziO3zRQTKtUL~n@7@gI)LZ$284#Db_C^Q6er?}^G$u*sY^#iXM*Dvv!El|}nulP^SM z?6V?|el{lW>c@Mo?}*7-$okw_QCagqO#Ue!lRX15dElCeJeYpt*qipj6P6_HPG7rEo5s65#mmD$+5v3xz=+o*}kgI~hl zjx|yF-CLvbZ+GDSbz4NbyF`9?KF;35hvGgn9FcD>ipg2aMgH=dnEchv(Eal`|Ks1W z7KBBg-R&{CYZGj8N=({ch{{WwBl7TBG5N$_N93|xOn&}5{C-6u zht8J|N9Cz+h@7zm?T)tIzdI_o{RBQ$ACnhXVm{O!l`nr6Z36jUzX0bjZjQ>Y z@qWrLe-M%9&x*+J@TG=Z*T-b;ZBgmTMdiNR(4MIG#3!Tjcynp;D%vCRp%GVF#na7(VvJ!L5k6=FfVXPZ` z3iGI6d_E>$L76}3iOJXSB1z-|@coU*JyS4Oe+F~8PhhTiYeXjRi^$&nB3m){j$^Lg z{9Sy?5c!uvr>CC6eED9H!=J(2@y3Yk{$5OeJ09oXohfo+J}P^6Mdd}5wc^E?T)ZP9 zb(jZt-;0y#F*p70!H5jh!~A-#_J%fuE8JPYS-@GqS-@GqS-@GqS-@GqS-@GqS-@G~ z4YUCF-{Vmz_S@naG|v7zAM@>}CwcAYDICBm-P8fad}7 zod7&07P8>*0>Km>=N(`NE#Mdc4+`X24$}Zr0X+8`({r5bCo%y5k!p&4EaKw;E;tJ~ z3pfin3pfin3pfin3pfin3pfin3pfin3%tG-FemoCzNNa-oCTZ(oCTZ(oCTZ(oCTZ( zoCTZ(oCTZ(oCTZ(oCTZ(oCTZ(oCTZ(oCTZ(oCTZ(oCTZ(oCTZ(oCTZ({yQ!3{{eCX BRs#S4 literal 0 HcmV?d00001 diff --git a/test/tools/llvm-pdbdump/class-layout.test b/test/tools/llvm-pdbdump/class-layout.test index c0083d176ea..ef5eb49af90 100644 --- a/test/tools/llvm-pdbdump/class-layout.test +++ b/test/tools/llvm-pdbdump/class-layout.test @@ -36,9 +36,8 @@ ; BASE_CLASS_D: ---TYPES--- ; BASE_CLASS_D: class BaseClassTest::D [sizeof = 8] -; BASE_CLASS_D-DAG: protected BaseClassTest::B -; BASE_CLASS_D-DAG: private BaseClassTest::C -; BASE_CLASS_D-DAG: protected virtual BaseClassTest::A +; BASE_CLASS_D-NEXT: protected BaseClassTest::B +; BASE_CLASS_D-NEXT: private BaseClassTest::C ; UDT_KIND_TEST: ---TYPES--- ; UDT_KIND_TEST-DAG: union UdtKindTest::C [sizeof = 1] {} diff --git a/test/tools/llvm-pdbdump/complex-padding-graphical.test b/test/tools/llvm-pdbdump/complex-padding-graphical.test new file mode 100644 index 00000000000..82881226e66 --- /dev/null +++ b/test/tools/llvm-pdbdump/complex-padding-graphical.test @@ -0,0 +1,53 @@ +; RUN: llvm-pdbdump pretty -classes -class-definitions=graphical \ +; RUN: -include-types=Test %p/Inputs/ComplexPaddingTest.pdb > %t + +; RUN: FileCheck -input-file=%t %s -check-prefix=DIRECT_VB_ONLY +; RUN: FileCheck -input-file=%t %s -check-prefix=DIRECT_VB_AND_NON_VB +; RUN: FileCheck -input-file=%t %s -check-prefix=INDIRECT_VB +; RUN: FileCheck -input-file=%t %s -check-prefix=INDIRECT_AND_DIRECT_VB + + +; DIRECT_VB_ONLY: struct TestIVBBase [sizeof = 16] +; DIRECT_VB_ONLY-NEXT: : public virtual TestVB { +; DIRECT_VB_ONLY-NEXT: vbptr +0x00 [sizeof=4] +; DIRECT_VB_ONLY-NEXT: data +0x04 [sizeof=4] int A +; DIRECT_VB_ONLY-NEXT: vbase +0x08 [sizeof=8] TestVB +; DIRECT_VB_ONLY-NEXT: vfptr +0x08 [sizeof=4] +; DIRECT_VB_ONLY-NEXT: data +0x0c [sizeof=4] int X +; DIRECT_VB_ONLY-NEXT: } + +DIRECT_VB_AND_NON_VB: struct TestVBLayout [sizeof = 24] +DIRECT_VB_AND_NON_VB-NEXT: : public TestNVB +DIRECT_VB_AND_NON_VB-NEXT: , public virtual TestVB { +DIRECT_VB_AND_NON_VB-NEXT: base +0x00 [sizeof=8] TestNVB +DIRECT_VB_AND_NON_VB-NEXT: vfptr +0x00 [sizeof=4] +DIRECT_VB_AND_NON_VB-NEXT: data +0x04 [sizeof=4] int Y +DIRECT_VB_AND_NON_VB-NEXT: vbptr +0x08 [sizeof=4] +DIRECT_VB_AND_NON_VB-NEXT: data +0x0c [sizeof=4] int Z +DIRECT_VB_AND_NON_VB-NEXT: vbase +0x10 [sizeof=8] TestVB +DIRECT_VB_AND_NON_VB-NEXT: vfptr +0x10 [sizeof=4] +DIRECT_VB_AND_NON_VB-NEXT: data +0x14 [sizeof=4] int X +DIRECT_VB_AND_NON_VB-NEXT: } + +INDIRECT_VB: struct TestIVBDerived [sizeof = 20] +INDIRECT_VB-NEXT: : public TestIVBBase { +INDIRECT_VB-NEXT: base +0x00 [sizeof=8] TestIVBBase +INDIRECT_VB-NEXT: vbptr +0x00 [sizeof=4] +INDIRECT_VB-NEXT: data +0x04 [sizeof=4] int A +INDIRECT_VB-NEXT: data +0x08 [sizeof=4] int B +INDIRECT_VB-NEXT: ivbase +0x0c [sizeof=8] TestVB +INDIRECT_VB-NEXT: vfptr +0x0c [sizeof=4] +INDIRECT_VB-NEXT: data +0x10 [sizeof=4] int X +INDIRECT_VB-NEXT: } + +INDIRECT_AND_DIRECT_VB: struct TestIVBMergedDerived [sizeof = 20] +INDIRECT_AND_DIRECT_VB-NEXT: : public TestIVBBase +INDIRECT_AND_DIRECT_VB-NEXT: , public virtual TestVB { +INDIRECT_AND_DIRECT_VB-NEXT: base +0x00 [sizeof=8] TestIVBBase +INDIRECT_AND_DIRECT_VB-NEXT: vbptr +0x00 [sizeof=4] +INDIRECT_AND_DIRECT_VB-NEXT: data +0x04 [sizeof=4] int A +INDIRECT_AND_DIRECT_VB-NEXT: data +0x08 [sizeof=4] int B +INDIRECT_AND_DIRECT_VB-NEXT: vbase +0x0c [sizeof=8] TestVB +INDIRECT_AND_DIRECT_VB-NEXT: vfptr +0x0c [sizeof=4] +INDIRECT_AND_DIRECT_VB-NEXT: data +0x10 [sizeof=4] int X +INDIRECT_AND_DIRECT_VB-NEXT: } diff --git a/test/tools/llvm-pdbdump/simple-padding-graphical.test b/test/tools/llvm-pdbdump/simple-padding-graphical.test index aacb0a33045..222349e75b0 100644 --- a/test/tools/llvm-pdbdump/simple-padding-graphical.test +++ b/test/tools/llvm-pdbdump/simple-padding-graphical.test @@ -71,7 +71,6 @@ ; 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: } @@ -89,15 +88,15 @@ ; 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: base +0x00 [sizeof=3] 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: (1 bytes) +; MULTIPLE_INHERIT2-NEXT: base +0x04 [sizeof=5] 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: (3 bytes) ; MULTIPLE_INHERIT2-NEXT: data +0x0c [sizeof=4] int X ; MULTIPLE_INHERIT2-NEXT: } diff --git a/test/tools/llvm-pdbdump/simple-padding-text.test b/test/tools/llvm-pdbdump/simple-padding-text.test deleted file mode 100644 index b33af565f65..00000000000 --- a/test/tools/llvm-pdbdump/simple-padding-text.test +++ /dev/null @@ -1,94 +0,0 @@ -; RUN: llvm-pdbdump pretty -classes -class-definitions=layout-members \ -; 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: } - -; 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: (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: (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: 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: (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: data +0x0c [sizeof=4] int X -; MULTIPLE_INHERIT2-NEXT: } - -; DEEP_INHERIT: struct SimplePadTwoLevelInherit [sizeof = 16] -; DEEP_INHERIT-NEXT: : public OneLevelInherit { -; 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: (3 bytes) -; AGGREGATE-NEXT: data +0x04 [sizeof=4] int Y -; AGGREGATE-NEXT: } diff --git a/tools/llvm-pdbdump/LinePrinter.cpp b/tools/llvm-pdbdump/LinePrinter.cpp index d4a5a8d859e..7fa524400ae 100644 --- a/tools/llvm-pdbdump/LinePrinter.cpp +++ b/tools/llvm-pdbdump/LinePrinter.cpp @@ -72,7 +72,7 @@ void LinePrinter::NewLine() { } bool LinePrinter::IsClassExcluded(const ClassLayout &Class) { - if (IsTypeExcluded(Class.getUDTName(), Class.getClassSize())) + if (IsTypeExcluded(Class.getName(), Class.getSize())) return true; if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold) return true; diff --git a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp index 9f213a4b4d9..81ef26167a2 100644 --- a/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp +++ b/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp @@ -58,25 +58,11 @@ void ClassDefinitionDumper::start(const ClassLayout &Layout) { 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(); - uint32_t Size = Layout.getClassSize(); + uint32_t Size = Layout.getSize(); const PDBSymbolTypeUDT &Class = Layout.getClass(); WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; @@ -84,19 +70,22 @@ void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) { WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size << "]"; uint32_t BaseCount = Layout.bases().size(); - uint32_t VBaseCount = Layout.vbases().size(); - uint32_t TotalBaseCount = BaseCount + VBaseCount; - if (TotalBaseCount > 0) { + if (BaseCount > 0) { Printer.Indent(); - Printer.NewLine(); - Printer << ":"; - uint32_t BaseIndex = 0; + char NextSeparator = ':'; for (auto BC : Layout.bases()) { const auto &Base = BC->getBase(); - printBase(Printer, Base, BaseIndex, TotalBaseCount, false); - } - for (auto &BC : Layout.vbases()) { - printBase(Printer, *BC, BaseIndex, TotalBaseCount, true); + if (Base.isIndirectVirtualBaseClass()) + continue; + + Printer.NewLine(); + Printer << NextSeparator << " "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess(); + if (BC->isVirtualBase()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual"; + + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName(); + NextSeparator = ','; } Printer.Unindent(); @@ -114,7 +103,7 @@ void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) { Printer.NewLine(); if (Layout.deepPaddingSize() > 0) { APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / - (double)Layout.getClassSize()); + (double)Layout.getSize()); SmallString<8> PctStr; Pct.toString(PctStr, 4); WithColor(Printer, PDB_ColorItem::Padding).get() diff --git a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp index d146ca9d471..f0385f198e0 100644 --- a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp +++ b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp @@ -53,15 +53,28 @@ bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) { } } - CurrentItem = Item.get(); - Item->getSymbol().dump(*this); + CurrentItem = Item; + if (Item->isVBPtr()) { + VTableLayoutItem &Layout = static_cast(*CurrentItem); + + VariableDumper VarDumper(Printer); + VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize()); + } else { + if (auto Sym = Item->getSymbol()) + Sym->dump(*this); + } + + if (Item->getLayoutSize() > 0) { + uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1; + NextPaddingByte = UseMap.find_next_unset(Prev); + } } - if (NextPaddingByte >= 0 && Layout.getClassSize() > 1) { - uint32_t Amount = Layout.getClassSize() - NextPaddingByte; + auto TailPadding = Layout.tailPadding(); + if (TailPadding > 0) { Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount - << " bytes)"; + WithColor(Printer, PDB_ColorItem::Padding).get() << " (" + << TailPadding << " bytes)"; DumpedAnything = true; } @@ -85,12 +98,19 @@ void PrettyClassLayoutGraphicalDumper::dump( Printer.NewLine(); BaseClassLayout &Layout = static_cast(*CurrentItem); - std::string Label = Layout.isVirtualBase() ? "vbase" : "base"; + std::string Label = "base"; + if (Layout.isVirtualBase()) { + Label.insert(Label.begin(), 'v'); + if (Layout.getBase().isIndirectVirtualBaseClass()) + Label.insert(Label.begin(), 'i'); + } Printer << Label << " "; + uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize(); + WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(CurrentAbsoluteOffset, 4) - << " [sizeof=" << Layout.getSize() << "] "; + << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size + << "] "; WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName(); @@ -125,27 +145,8 @@ void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) { 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 7dfb74c4e14..61b62b1762a 100644 --- a/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h +++ b/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h @@ -19,7 +19,7 @@ namespace llvm { namespace pdb { class UDTLayoutBase; -class StorageItemBase; +class LayoutItemBase; class LinePrinter; class PrettyClassLayoutGraphicalDumper : public PDBSymDumper { @@ -37,7 +37,7 @@ private: LinePrinter &Printer; - StorageItemBase *CurrentItem = nullptr; + LayoutItemBase *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 02f31108b0d..ccfd38c1e3c 100644 --- a/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp +++ b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.cpp @@ -59,14 +59,17 @@ bool PrettyClassLayoutTextDumper::start(const ClassLayout &Layout) { NextUnusedByte = UseMap.find_next_unset(Off); } } - LayoutItem->getSymbol().dump(*this); + if (auto Sym = LayoutItem->getSymbol()) + Sym->dump(*this); } - if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) { - uint32_t Amount = Layout.getClassSize() - NextUnusedByte; - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount - << " bytes)"; + if (NextUnusedByte >= 0 && Layout.getSize() > 1) { + uint32_t Amount = Layout.getSize() - NextUnusedByte; + if (Amount > 0) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() << " (" + << Amount << " bytes)"; + } DumpedAnything = true; } @@ -116,4 +119,6 @@ void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeTypedef &Symbol) { Dumper.start(Symbol); } +void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {} + void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeUDT &Symbol) {} diff --git a/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h index 56c20f0e843..1adbbffce55 100644 --- a/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h +++ b/tools/llvm-pdbdump/PrettyClassLayoutTextDumper.h @@ -34,6 +34,7 @@ public: void dump(const PDBSymbolTypeTypedef &Symbol) override; void dump(const PDBSymbolTypeUDT &Symbol) override; void dump(const PDBSymbolTypeVTable &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; private: bool DumpedAnything = false; diff --git a/tools/llvm-pdbdump/PrettyTypeDumper.cpp b/tools/llvm-pdbdump/PrettyTypeDumper.cpp index ffeef72150d..324a26f9a24 100644 --- a/tools/llvm-pdbdump/PrettyTypeDumper.cpp +++ b/tools/llvm-pdbdump/PrettyTypeDumper.cpp @@ -34,17 +34,23 @@ 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(); + return S1->getName() < S2->getName(); } static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) { - return S1->getClassSize() < S2->getClassSize(); + return S1->getSize() < S2->getSize(); } static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) { return S1->deepPaddingSize() < S2->deepPaddingSize(); } +static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) { + double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize(); + double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize(); + return Pct1 < Pct2; +} + static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { switch (Mode) { case opts::pretty::ClassSortMode::Name: @@ -53,6 +59,8 @@ static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { return CompareSizes; case opts::pretty::ClassSortMode::Padding: return ComparePadding; + case opts::pretty::ClassSortMode::PaddingPct: + return ComparePaddingPct; default: return nullptr; } @@ -67,14 +75,18 @@ filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E, Filtered.reserve(UnfilteredCount); CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder); + if (UnfilteredCount > 10000) { + errs() << formatv("Filtering and sorting {0} types", UnfilteredCount); + errs().flush(); + } uint32_t Examined = 0; uint32_t Discarded = 0; while (auto Class = E.getNext()) { ++Examined; if (Examined % 10000 == 0) { - outs() << formatv("Examined {0}/{1} items. {2} items discarded\n", + errs() << formatv("Examined {0}/{1} items. {2} items discarded\n", Examined, UnfilteredCount, Discarded); - outs().flush(); + errs().flush(); } if (Class->getUnmodifiedTypeId() != 0) { @@ -163,6 +175,9 @@ void TypeDumper::start(const PDBSymbolExe &Exe) { dumpClassLayout(*Class); } else { while (auto Class = Classes->getNext()) { + if (Class->getUnmodifiedTypeId() != 0) + continue; + if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) continue; @@ -209,7 +224,7 @@ void TypeDumper::dumpClassLayout(const ClassLayout &Class) { if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; - WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getUDTName(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName(); } else { ClassDefinitionDumper Dumper(Printer); Dumper.start(Class); diff --git a/tools/llvm-pdbdump/PrettyVariableDumper.cpp b/tools/llvm-pdbdump/PrettyVariableDumper.cpp index 76a0d23bf87..70925f4b03d 100644 --- a/tools/llvm-pdbdump/PrettyVariableDumper.cpp +++ b/tools/llvm-pdbdump/PrettyVariableDumper.cpp @@ -91,6 +91,14 @@ void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) { } } +void VariableDumper::startVbptr(uint32_t Offset, uint32_t Size) { + Printer.NewLine(); + Printer << "vbptr "; + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset, 4) << " [sizeof=" << Size << "] "; +} + void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) { Printer.NewLine(); Printer << "vfptr "; diff --git a/tools/llvm-pdbdump/PrettyVariableDumper.h b/tools/llvm-pdbdump/PrettyVariableDumper.h index 4ba3bc97d85..cacf1ce9577 100644 --- a/tools/llvm-pdbdump/PrettyVariableDumper.h +++ b/tools/llvm-pdbdump/PrettyVariableDumper.h @@ -26,6 +26,7 @@ public: void start(const PDBSymbolData &Var, uint32_t Offset = 0); void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0); + void startVbptr(uint32_t Offset, uint32_t Size); 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 06c2afc0bc7..d51f64065d6 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -124,12 +124,15 @@ 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::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"), + clEnumValN(ClassSortMode::PaddingPct, "padding-pct", + "Sort classes by percentage of space consumed by padding")), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt ClassFormat( diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h index a5429a253df..f77124de0ba 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/tools/llvm-pdbdump/llvm-pdbdump.h @@ -19,7 +19,7 @@ namespace opts { namespace pretty { enum class ClassDefinitionFormat { None, Layout, Graphical, Standard }; -enum class ClassSortMode { None, Name, Size, Padding }; +enum class ClassSortMode { None, Name, Size, Padding, PaddingPct }; extern llvm::cl::opt Compilands; extern llvm::cl::opt Symbols; -- 2.50.1