std::unique_ptr<ChildType> getChildAtIndex(uint32_t Index) const override {
std::unique_ptr<PDBSymbol> Child = Enumerator->getChildAtIndex(Index);
- return make_concrete_child(std::move(Child));
+ return unique_dyn_cast_or_null<ChildType>(Child);
}
std::unique_ptr<ChildType> getNext() override {
- std::unique_ptr<PDBSymbol> Child = Enumerator->getNext();
- return make_concrete_child(std::move(Child));
+ return unique_dyn_cast_or_null<ChildType>(Enumerator->getNext());
}
void reset() override { Enumerator->reset(); }
}
private:
- std::unique_ptr<ChildType>
- make_concrete_child(std::unique_ptr<PDBSymbol> Child) const {
- ChildType *ConcreteChild = dyn_cast_or_null<ChildType>(Child.release());
- return std::unique_ptr<ChildType>(ConcreteChild);
- }
std::unique_ptr<IPDBEnumSymbols> Enumerator;
};
void dump(PDBSymDumper &Dumper) const override;
+ bool isDestructor() const;
+
std::unique_ptr<IPDBEnumChildren<PDBSymbolData>> getArguments() const;
DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::Function)
virtual uint32_t deepPaddingSize() const;
const PDBSymbolData &getDataMember();
+ bool hasUDTLayout() const;
+ const ClassLayout &getUDTLayout() const;
private:
std::unique_ptr<PDBSymbolData> DataMember;
public:
VTableLayoutItem(const UDTLayoutBase &Parent,
std::unique_ptr<PDBSymbolTypeVTable> VTable);
+ ArrayRef<PDBSymbolFunc *> 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<PDBSymbolTypeVTableShape> Shape;
std::unique_ptr<PDBSymbolTypeVTable> VTable;
- std::vector<std::unique_ptr<PDBSymbolFunc>> VTableFuncs;
+ std::vector<PDBSymbolFunc *> VTableFuncs;
};
class UDTLayoutBase {
+ template <typename T> using UniquePtrVector = std::vector<std::unique_ptr<T>>;
+
public:
UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name,
uint32_t Size);
return ChildStorage;
}
- ArrayRef<BaseClassLayout *> base_classes() const { return BaseClasses; }
+ VTableLayoutItem *findVTableAtOffset(uint32_t RelativeOffset);
- ArrayRef<std::unique_ptr<PDBSymbol>> other_items() const {
- return NonStorageItems;
+ StringRef getUDTName() const { return Name; }
+
+ ArrayRef<BaseClassLayout *> bases() const { return BaseClasses; }
+ ArrayRef<std::unique_ptr<PDBSymbolTypeBaseClass>> vbases() const {
+ return VirtualBases;
}
+ ArrayRef<std::unique_ptr<PDBSymbolFunc>> funcs() const { return Funcs; }
+
+ ArrayRef<std::unique_ptr<PDBSymbol>> other_items() const { return Other; }
+
const PDBSymbol &getSymbolBase() const { return SymbolBase; }
protected:
void initializeChildren(const PDBSymbol &Sym);
void addChildToLayout(std::unique_ptr<StorageItemBase> Child);
+ void addVirtualOverride(PDBSymbolFunc &Func);
+ void addVirtualIntro(PDBSymbolFunc &Func);
const PDBSymbol &SymbolBase;
std::string Name;
uint32_t SizeOf = 0;
BitVector UsedBytes;
- std::vector<std::unique_ptr<PDBSymbol>> NonStorageItems;
- std::vector<std::unique_ptr<StorageItemBase>> ChildStorage;
+ UniquePtrVector<PDBSymbol> Other;
+ UniquePtrVector<PDBSymbolFunc> Funcs;
+ UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBases;
+ UniquePtrVector<StorageItemBase> ChildStorage;
std::vector<std::list<StorageItemBase *>> ChildrenPerByte;
std::vector<BaseClassLayout *> BaseClasses;
VTableLayoutItem *VTable = nullptr;
explicit ClassLayout(const PDBSymbolTypeUDT &UDT);
explicit ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT);
+ ClassLayout(ClassLayout &&Other) = default;
+
const PDBSymbolTypeUDT &getClass() const { return UDT; }
private:
std::unique_ptr<PDBSymbolTypeBaseClass> Base);
const PDBSymbolTypeBaseClass &getBase() const { return *Base; }
+ bool isVirtualBase() const { return IsVirtualBase; }
private:
std::unique_ptr<PDBSymbolTypeBaseClass> Base;
std::unique_ptr<IPDBEnumSymbols>
PDBSymbol::getChildStats(TagStats &Stats) const {
std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren());
+ if (!Result)
+ return nullptr;
Stats.clear();
while (auto Child = Result->getNext()) {
++Stats[Child->getSymTag()];
}
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;
+}
#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"
return *dyn_cast<PDBSymbolData>(&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)
std::unique_ptr<PDBSymbolTypeVTable> VTable)
: StorageItemBase(Parent, *VTable, "<vtbl>", 0, getTypeLength(*VTable)),
VTable(std::move(VTable)) {
- // initialize vtbl methods.
auto VTableType = cast<PDBSymbolTypePointer>(this->VTable->getType());
- uint32_t PointerSize = VTableType->getLength();
+ ElementSize = VTableType->getLength();
- if (auto Shape = unique_dyn_cast<PDBSymbolTypeVTableShape>(
- VTableType->getPointeeType())) {
+ Shape =
+ unique_dyn_cast<PDBSymbolTypeVTableShape>(VTableType->getPointeeType());
+ if (Shape)
VTableFuncs.resize(Shape->getCount());
-
- auto ParentFunctions =
- Parent.getSymbolBase().findAllChildren<PDBSymbolFunc>();
- 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,
}
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<PDBSymbolTypeBaseClass> Bases;
+ UniquePtrVector<PDBSymbolTypeVTable> VTables;
+ UniquePtrVector<PDBSymbolData> Members;
auto Children = Sym.findAllChildren();
while (auto Child = Children->getNext()) {
- if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) {
- if (Data->getDataKind() == PDB_DataKind::Member) {
- auto DM =
- llvm::make_unique<DataMemberLayoutItem>(*this, std::move(Data));
-
- addChildToLayout(std::move(DM));
- } else {
- NonStorageItems.push_back(std::move(Data));
- }
- continue;
+ if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
+ if (Base->isVirtualBaseClass())
+ VirtualBases.push_back(std::move(Base));
+ else
+ Bases.push_back(std::move(Base));
}
- if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
- auto BL = llvm::make_unique<BaseClassLayout>(*this, std::move(Base));
- BaseClasses.push_back(BL.get());
+ else if (auto Data = unique_dyn_cast<PDBSymbolData>(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<PDBSymbolTypeVTable>(Child))
+ VTables.push_back(std::move(VT));
+ else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(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<BaseClassLayout>(*this, std::move(Base));
+ BaseClasses.push_back(BL.get());
+
+ addChildToLayout(std::move(BL));
+ }
+
+ for (auto &VT : VTables) {
+ auto VTLayout = llvm::make_unique<VTableLayoutItem>(*this, std::move(VT));
+
+ VTable = VTLayout.get();
+
+ addChildToLayout(std::move(VTLayout));
+ continue;
+ }
+
+ for (auto &Data : Members) {
+ auto DM = llvm::make_unique<DataMemberLayoutItem>(*this, std::move(Data));
+
+ addChildToLayout(std::move(DM));
+ }
+
+ for (auto &Func : Funcs) {
+ if (!Func->isVirtual())
continue;
- }
- if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) {
- auto VTLayout = llvm::make_unique<VTableLayoutItem>(*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<StorageItemBase> 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());
// 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;
--- /dev/null
+; 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: <padding> (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: <padding> (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: <padding> (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: <padding> (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: <padding> (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: <padding> (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: <padding> (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: <padding> (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: <padding> (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: <padding> (1 bytes)
+; DEEP_INHERIT-NEXT: data +0x02 [sizeof=2] short Y
+; DEEP_INHERIT-NEXT: <padding> (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: <padding> (3 bytes)
+; AGGREGATE-NEXT: data +0x04 [sizeof=4] int Y
+; AGGREGATE-NEXT: }
; 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: }
#include "llvm-pdbdump.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
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) {
namespace llvm {
namespace pdb {
+class ClassLayout;
+
class LinePrinter {
friend class WithColor;
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);
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;
}
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();
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();
}
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);
#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() << "<padding> (" << Amount
+ << " bytes)";
+ DumpedAnything = true;
+ }
+
+ return DumpedAnything;
+}
+
+void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) {
+ if (Amount == 0)
+ return;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << 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<BaseClassLayout &>(*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<DataMemberLayoutItem &>(*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<VTableLayoutItem &>(*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<PDBSymbolTypeUDT>(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;
}
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;
};
}
}
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();
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeEnum &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
DumpedAnything = true;
Printer.NewLine();
EnumDumper Dumper(Printer);
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
- if (Printer.IsTypeExcluded(Symbol.getName()))
- return;
-
DumpedAnything = true;
Printer.NewLine();
TypedefDumper Dumper(Printer);
#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<ClassLayout>;
+
+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 <typename Enumerator>
-static std::vector<std::unique_ptr<PDBSymbolTypeUDT>>
-filterClassDefs(LinePrinter &Printer, Enumerator &E) {
- std::vector<std::unique_ptr<PDBSymbolTypeUDT>> Filtered;
+static std::vector<std::unique_ptr<ClassLayout>>
+filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E,
+ uint32_t UnfilteredCount) {
+ std::vector<std::unique_ptr<ClassLayout>> 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<ClassLayout>(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;
}
if (opts::pretty::Classes) {
auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
- auto Filtered = filterClassDefs(Printer, *Classes);
-
- Printer.NewLine();
- uint32_t Shown = Filtered.size();
uint32_t All = Classes->getChildCount();
+ 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<LayoutPtr> 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<ClassLayout>(std::move(Class));
+ if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold)
+ continue;
+
+ dumpClassLayout(*Layout);
+ }
+ }
+
Printer.Unindent();
}
}
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())
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();
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);
}
}
namespace llvm {
namespace pdb {
class LinePrinter;
+class ClassLayout;
class TypeDumper : public PDBSymDumper {
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;
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()))
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();
}
}
-void VariableDumper::start(const PDBSymbolTypeVTable &Var) {
+void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) {
Printer.NewLine();
- Printer << "data ";
+ Printer << "vfptr ";
auto VTableType = cast<PDBSymbolTypePointer>(Var.getType());
uint32_t PointerSize = VTableType->getLength();
WithColor(Printer, PDB_ColorItem::Offset).get()
- << "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << PointerSize
- << "] ";
-
- WithColor(Printer, PDB_ColorItem::Identifier).get() << " __vfptr";
+ << "+" << format_hex(Offset + Var.getOffset(), 4)
+ << " [sizeof=" << PointerSize << "] ";
}
void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) {
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;
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"),
cl::cat(TypeCategory), cl::sub(PrettySubcommand));
+cl::opt<ClassSortMode> 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<ClassDefinitionFormat> 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));
"include-compilands",
cl::desc("Include only compilands those which match a regular expression"),
cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand));
-cl::opt<bool> 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<uint32_t> 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<uint32_t> 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<bool> ExcludeCompilerGenerated(
"no-compiler-generated",
namespace pretty {
enum class ClassDefinitionFormat { None, Layout, Graphical, Standard };
+enum class ClassSortMode { None, Name, Size, Padding };
extern llvm::cl::opt<bool> Compilands;
extern llvm::cl::opt<bool> Symbols;
extern llvm::cl::list<std::string> IncludeTypes;
extern llvm::cl::list<std::string> IncludeSymbols;
extern llvm::cl::list<std::string> IncludeCompilands;
-extern llvm::cl::opt<bool> OnlyPaddingClasses;
+extern llvm::cl::opt<ClassSortMode> ClassOrder;
+extern llvm::cl::opt<uint32_t> SizeThreshold;
+extern llvm::cl::opt<uint32_t> PaddingThreshold;
extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
}