[llvm-pdbdump] Recursively dump class layout.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300258 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Zachary Turner 2017-04-13 21:11:00 +00:00
parent a402bd1ba7
commit 10683346a5
23 changed files with 734 additions and 142 deletions

View File

@ -34,12 +34,11 @@ public:
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(); }
@ -50,11 +49,6 @@ public:
}
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;
};

View File

@ -27,6 +27,8 @@ public:
void dump(PDBSymDumper &Dumper) const override;
bool isDestructor() const;
std::unique_ptr<IPDBEnumChildren<PDBSymbolData>> getArguments() const;
DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::Function)

View File

@ -67,6 +67,8 @@ public:
virtual uint32_t deepPaddingSize() const;
const PDBSymbolData &getDataMember();
bool hasUDTLayout() const;
const ClassLayout &getUDTLayout() const;
private:
std::unique_ptr<PDBSymbolData> DataMember;
@ -77,13 +79,24 @@ class VTableLayoutItem : public StorageItemBase {
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);
@ -99,26 +112,37 @@ public:
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;
@ -129,6 +153,8 @@ public:
explicit ClassLayout(const PDBSymbolTypeUDT &UDT);
explicit ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT);
ClassLayout(ClassLayout &&Other) = default;
const PDBSymbolTypeUDT &getClass() const { return UDT; }
private:
@ -142,6 +168,7 @@ public:
std::unique_ptr<PDBSymbolTypeBaseClass> Base);
const PDBSymbolTypeBaseClass &getBase() const { return *Base; }
bool isVirtualBase() const { return IsVirtualBase; }
private:
std::unique_ptr<PDBSymbolTypeBaseClass> Base;

View File

@ -159,6 +159,8 @@ PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const {
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()];

View File

@ -95,3 +95,14 @@ PDBSymbolFunc::getArguments() const {
}
void PDBSymbolFunc::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
bool PDBSymbolFunc::isDestructor() const {
std::string Name = getName();
if (Name.empty())
return false;
if (Name[0] == '~')
return true;
if (Name == "__vecDelDtor")
return true;
return false;
}

View File

@ -9,6 +9,7 @@
#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
@ -70,6 +71,12 @@ const PDBSymbolData &DataMemberLayoutItem::getDataMember() {
return *dyn_cast<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)
@ -81,31 +88,13 @@ VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,
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,
@ -145,44 +134,191 @@ uint32_t UDTLayoutBase::deepPaddingSize() const {
}
void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) {
// Handled bases first, followed by VTables, followed by data members,
// followed by functions, followed by other. This ordering is necessary
// so that bases and vtables get initialized before any functions which
// may override them.
UniquePtrVector<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));
if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
if (Base->isVirtualBaseClass())
VirtualBases.push_back(std::move(Base));
else
Bases.push_back(std::move(Base));
}
addChildToLayout(std::move(DM));
} else {
NonStorageItems.push_back(std::move(Data));
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));
}
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 (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;
}
uint32_t Stride = VTable->getElementSize();
uint32_t Index = Func.getVirtualBaseOffset();
assert(Index % Stride == 0);
Index /= Stride;
VTable->setFunction(Index, Func);
}
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;
}
if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
auto BL = llvm::make_unique<BaseClassLayout>(*this, std::move(Base));
BaseClasses.push_back(BL.get());
addChildToLayout(std::move(BL));
// 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 (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) {
auto VTLayout = llvm::make_unique<VTableLayoutItem>(*this, std::move(VT));
VTable = VTLayout.get();
addChildToLayout(std::move(VTLayout));
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());

View File

@ -116,6 +116,51 @@ struct SimplePadAggregate {
// the presence of X will cause 3 bytes of padding to be injected.
} N;
struct SimplePadVtable1 {
static void operator delete(void *ptr, size_t sz) {}
virtual ~SimplePadVtable1() {}
virtual void A1() {}
virtual void B1() {}
} O;
struct SimplePadVtable2 {
static void operator delete(void *ptr, size_t sz) {}
virtual ~SimplePadVtable2() {}
virtual void X2() {}
virtual void Y2() {}
virtual void Z2() {}
} P;
struct SimplePadVtable3 {
static void operator delete(void *ptr, size_t sz) {}
virtual ~SimplePadVtable3() {}
virtual void Foo3() {}
virtual void Bar3() {}
virtual void Baz3() {}
virtual void Buzz3() {}
} Q;
struct SimplePadMultiVTables
: public SimplePadVtable1,
public SimplePadVtable2,
public SimplePadVtable3 {
~SimplePadMultiVTables() override {}
static void operator delete(void *ptr, size_t sz) {}
// SimplePadVtable1 overrides
void A1() override {}
// SimplePadVtable2 overrides
void Y2() override {}
void Z2() override {}
// SimplePadVtable3 overrides
void Bar3() override {}
void Baz3() override {}
void Buzz3() override {}
} R;
int main(int argc, char **argv) {
return 0;

View File

@ -0,0 +1,121 @@
; RUN: llvm-pdbdump pretty -classes -class-definitions=graphical \
; RUN: -include-types=SimplePad %p/Inputs/SimplePaddingTest.pdb > %t
; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PADDING
; RUN: FileCheck -input-file=%t %s -check-prefix=UNION
; RUN: FileCheck -input-file=%t %s -check-prefix=NESTED_UNION
; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS1
; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS2
; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PAD_IN_BASE
; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_IN_DERIVED
; RUN: FileCheck -input-file=%t %s -check-prefix=EMPTY_BASE
; RUN: FileCheck -input-file=%t %s -check-prefix=VFPTR
; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT
; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT2
; RUN: FileCheck -input-file=%t %s -check-prefix=DEEP_INHERIT
; RUN: FileCheck -input-file=%t %s -check-prefix=AGGREGATE
; NO_PADDING: struct SimplePadNoPadding [sizeof = 8] {
; NO_PADDING-NEXT: data +0x00 [sizeof=4] int X
; NO_PADDING-NEXT: data +0x04 [sizeof=4] int Y
; NO_PADDING-NEXT: }
; UNION: struct SimplePadUnion [sizeof = 16] {
; UNION-NEXT: data +0x00 [sizeof=4] int X
; UNION-NEXT: data +0x00 [sizeof=8] __int64 Y
; UNION-NEXT: data +0x00 [sizeof=16] SimplePadUnion::
; UNION-NEXT: data +0x00 [sizeof=4] int X
; UNION-NEXT: <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: }

View File

@ -63,7 +63,7 @@
; EMPTY_BASE-NEXT: }
; VFPTR: struct SimplePadVfptr [sizeof = 8] {
; VFPTR-NEXT: data +0x00 [sizeof=4] __vfptr
; VFPTR-NEXT: vfptr +0x00 [sizeof=4]
; VFPTR-NEXT: data +0x04 [sizeof=4] int X
; VFPTR-NEXT: }

View File

@ -12,6 +12,7 @@
#include "llvm-pdbdump.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
@ -70,8 +71,20 @@ void LinePrinter::NewLine() {
OS.indent(CurrentIndent);
}
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName) {
return IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters);
bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
if (IsTypeExcluded(Class.getUDTName(), Class.getClassSize()))
return true;
if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold)
return true;
return false;
}
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
return true;
if (Size < opts::pretty::SizeThreshold)
return true;
return false;
}
bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {

View File

@ -20,6 +20,8 @@
namespace llvm {
namespace pdb {
class ClassLayout;
class LinePrinter {
friend class WithColor;
@ -34,7 +36,8 @@ public:
raw_ostream &getStream() { return OS; }
int getIndentLevel() const { return CurrentIndent; }
bool IsTypeExcluded(llvm::StringRef TypeName);
bool IsClassExcluded(const ClassLayout &Class);
bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size);
bool IsSymbolExcluded(llvm::StringRef SymbolName);
bool IsCompilandExcluded(llvm::StringRef CompilandName);

View File

@ -33,15 +33,15 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
opts::pretty::ClassDefinitionFormat::None);
ClassLayout Layout(Class);
start(Layout);
}
if (opts::pretty::OnlyPaddingClasses && (Layout.shallowPaddingSize() == 0))
return;
void ClassDefinitionDumper::start(const ClassLayout &Layout) {
prettyPrintClassIntro(Layout);
switch (opts::pretty::ClassFormat) {
case opts::pretty::ClassDefinitionFormat::Graphical: {
PrettyClassLayoutGraphicalDumper Dumper(Printer);
PrettyClassLayoutGraphicalDumper Dumper(Printer, 0);
DumpedAnything = Dumper.start(Layout);
break;
}
@ -58,6 +58,20 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
prettyPrintClassOutro(Layout);
}
static void printBase(LinePrinter &Printer, const PDBSymbolTypeBaseClass &Base,
uint32_t &CurIndex, uint32_t TotalBaseCount,
bool IsVirtual) {
Printer << " ";
WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
if (IsVirtual)
WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
if (++CurIndex < TotalBaseCount) {
Printer.NewLine();
Printer << ",";
}
}
void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) {
DumpedAnything = false;
Printer.NewLine();
@ -69,24 +83,22 @@ void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) {
WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
<< "]";
uint32_t BaseCount = Layout.base_classes().size();
if (BaseCount > 0) {
uint32_t BaseCount = Layout.bases().size();
uint32_t VBaseCount = Layout.vbases().size();
uint32_t TotalBaseCount = BaseCount + VBaseCount;
if (TotalBaseCount > 0) {
Printer.Indent();
Printer.NewLine();
Printer << ":";
uint32_t BaseIndex = 0;
for (auto BC : Layout.base_classes()) {
for (auto BC : Layout.bases()) {
const auto &Base = BC->getBase();
Printer << " ";
WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess();
if (Base.isVirtualBaseClass())
WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName();
if (++BaseIndex < BaseCount) {
Printer.NewLine();
Printer << ",";
}
printBase(Printer, Base, BaseIndex, TotalBaseCount, false);
}
for (auto &BC : Layout.vbases()) {
printBase(Printer, *BC, BaseIndex, TotalBaseCount, true);
}
Printer.Unindent();
}

View File

@ -32,7 +32,8 @@ class ClassDefinitionDumper : public PDBSymDumper {
public:
ClassDefinitionDumper(LinePrinter &P);
void start(const PDBSymbolTypeUDT &Exe);
void start(const PDBSymbolTypeUDT &Class);
void start(const ClassLayout &Class);
private:
void prettyPrintClassIntro(const ClassLayout &Class);

View File

@ -9,30 +9,143 @@
#include "PrettyClassLayoutGraphicalDumper.h"
#include "LinePrinter.h"
#include "PrettyClassDefinitionDumper.h"
#include "PrettyVariableDumper.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Format.h"
using namespace llvm;
using namespace llvm::pdb;
PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper(
LinePrinter &P)
: PDBSymDumper(true) {}
LinePrinter &P, uint32_t InitialOffset)
: PDBSymDumper(true), Printer(P), ClassOffsetZero(InitialOffset),
CurrentAbsoluteOffset(InitialOffset) {}
bool PrettyClassLayoutGraphicalDumper::start(const ClassLayout &Layout) {
return false;
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);
}
}
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;
}

View File

@ -18,22 +18,29 @@ namespace llvm {
namespace pdb {
class ClassLayout;
class UDTLayoutBase;
class StorageItemBase;
class LinePrinter;
class PrettyClassLayoutGraphicalDumper : public PDBSymDumper {
public:
explicit PrettyClassLayoutGraphicalDumper(LinePrinter &P);
PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t InitialOffset);
bool start(const ClassLayout &Layout);
bool start(const UDTLayoutBase &Layout);
void dump(const PDBSymbolTypeBaseClass &Symbol) override;
void dump(const PDBSymbolData &Symbol) override;
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolFunc &Symbol) override;
void dump(const PDBSymbolTypeTypedef &Symbol) override;
void dump(const PDBSymbolTypeUDT &Symbol) override;
void dump(const PDBSymbolTypeVTable &Symbol) override;
private:
void printPaddingRow(uint32_t Amount);
LinePrinter &Printer;
StorageItemBase *CurrentItem = nullptr;
uint32_t ClassOffsetZero = 0;
uint32_t CurrentAbsoluteOffset = 0;
bool DumpedAnything = false;
};
}
}

View File

@ -38,6 +38,8 @@ bool PrettyClassLayoutTextDumper::start(const ClassLayout &Layout) {
opts::pretty::ClassDefinitionFormat::Standard) {
for (auto &Other : Layout.other_items())
Other->dump(*this);
for (auto &Func : Layout.funcs())
Func->dump(*this);
}
const BitVector &UseMap = Layout.usedBytes();
@ -101,9 +103,6 @@ void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeVTable &Symbol) {
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeEnum &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
DumpedAnything = true;
Printer.NewLine();
EnumDumper Dumper(Printer);
@ -111,9 +110,6 @@ void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeEnum &Symbol) {
}
void PrettyClassLayoutTextDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
DumpedAnything = true;
Printer.NewLine();
TypedefDumper Dumper(Printer);

View File

@ -22,24 +22,82 @@
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/FormatVariadic.h"
using namespace llvm;
using namespace llvm::pdb;
using LayoutPtr = std::unique_ptr<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)
continue;
++Examined;
if (Examined % 10000 == 0) {
outs() << formatv("Examined {0}/{1} items. {2} items discarded\n",
Examined, UnfilteredCount, Discarded);
outs().flush();
}
if (Printer.IsTypeExcluded(Class->getName()))
if (Class->getUnmodifiedTypeId() != 0) {
++Discarded;
continue;
}
Filtered.push_back(std::move(Class));
if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) {
++Discarded;
continue;
}
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;
}
@ -70,20 +128,52 @@ void TypeDumper::start(const PDBSymbolExe &Exe) {
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();
}
}
@ -91,7 +181,7 @@ void TypeDumper::start(const PDBSymbolExe &Exe) {
void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
assert(opts::pretty::Enums);
if (Printer.IsTypeExcluded(Symbol.getName()))
if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
return;
// Dump member enums when dumping their class definition.
if (nullptr != Symbol.getClassParent())
@ -105,7 +195,7 @@ void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
assert(opts::pretty::Typedefs);
if (Printer.IsTypeExcluded(Symbol.getName()))
if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength()))
return;
Printer.NewLine();
@ -113,15 +203,15 @@ void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
Dumper.start(Symbol);
}
void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
void TypeDumper::dumpClassLayout(const ClassLayout &Class) {
assert(opts::pretty::Classes);
if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
Printer.NewLine();
WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getUDTName();
} else {
ClassDefinitionDumper Dumper(Printer);
Dumper.start(Symbol);
Dumper.start(Class);
}
}

View File

@ -15,6 +15,7 @@
namespace llvm {
namespace pdb {
class LinePrinter;
class ClassLayout;
class TypeDumper : public PDBSymDumper {
public:
@ -24,7 +25,8 @@ public:
void dump(const PDBSymbolTypeEnum &Symbol) override;
void dump(const PDBSymbolTypeTypedef &Symbol) override;
void dump(const PDBSymbolTypeUDT &Symbol) override;
void dumpClassLayout(const ClassLayout &Class);
private:
LinePrinter &Printer;

View File

@ -35,7 +35,7 @@ using namespace llvm::pdb;
VariableDumper::VariableDumper(LinePrinter &P)
: PDBSymDumper(true), Printer(P) {}
void VariableDumper::start(const PDBSymbolData &Var) {
void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) {
if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
return;
if (Printer.IsSymbolExcluded(Var.getName()))
@ -68,16 +68,16 @@ void VariableDumper::start(const PDBSymbolData &Var) {
Printer.NewLine();
Printer << "data ";
WithColor(Printer, PDB_ColorItem::Offset).get()
<< "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << Length
<< "] ";
<< "+" << format_hex(Offset + Var.getOffset(), 4)
<< " [sizeof=" << Length << "] ";
dumpSymbolTypeAndName(*VarType, Var.getName());
break;
case PDB_LocType::BitField:
Printer.NewLine();
Printer << "data ";
WithColor(Printer, PDB_ColorItem::Offset).get()
<< "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << Length
<< "] ";
<< "+" << format_hex(Offset + Var.getOffset(), 4)
<< " [sizeof=" << Length << "] ";
dumpSymbolTypeAndName(*VarType, Var.getName());
Printer << " : ";
WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
@ -91,17 +91,15 @@ void VariableDumper::start(const PDBSymbolData &Var) {
}
}
void VariableDumper::start(const PDBSymbolTypeVTable &Var) {
void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) {
Printer.NewLine();
Printer << "data ";
Printer << "vfptr ";
auto VTableType = cast<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) {

View File

@ -24,8 +24,8 @@ class VariableDumper : public PDBSymDumper {
public:
VariableDumper(LinePrinter &P);
void start(const PDBSymbolData &Var);
void start(const PDBSymbolTypeVTable &Var);
void start(const PDBSymbolData &Var, uint32_t Offset = 0);
void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0);
void dump(const PDBSymbolTypeArray &Symbol) override;
void dump(const PDBSymbolTypeBuiltin &Symbol) override;

View File

@ -122,15 +122,27 @@ cl::opt<bool> Enums("enums", cl::desc("Display enum types"),
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));
@ -173,10 +185,14 @@ cl::list<std::string> IncludeCompilands(
"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",

View File

@ -19,6 +19,7 @@ namespace opts {
namespace pretty {
enum class ClassDefinitionFormat { None, Layout, Graphical, Standard };
enum class ClassSortMode { None, Name, Size, Padding };
extern llvm::cl::opt<bool> Compilands;
extern llvm::cl::opt<bool> Symbols;
@ -36,7 +37,9 @@ extern llvm::cl::list<std::string> ExcludeCompilands;
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;
}