llvm.org GIT mirror llvm / 7724dc6
[llvm-pdbdump] More advanced class definition dumping. Previously the dumping of class definitions was very primitive, and it made it hard to do more than the most trivial of output formats when dumping. As such, we would only dump one line for each field, and then dump non-layout items like nested types and enums. With this patch, we do a complete analysis of the object hierarchy including aggregate types, bases, virtual bases, vftable analysis, etc. The only immediately visible effects of this are that a) we can now dump a line for the vfptr where before we would treat that as padding, and b) we now don't treat virtual bases that come at the end of a class as padding since we have a more detailed analysis of the class's storage usage. In subsequent patches, we should be able to use this analysis to display a complete graphical view of a class's layout including recursing arbitrarily deep into an object's base class / aggregate member hierarchy. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300133 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 2 years ago
39 changed file(s) with 769 addition(s) and 155 deletion(s). Raw diff Collapse all Expand all
101101 uint32_t getVirtualBaseDispIndex() const override;
102102 uint32_t getVirtualBaseOffset() const override;
103103 uint32_t getVirtualTableShapeId() const override;
104 std::unique_ptr getVirtualBaseTableType() const override;
104105 PDB_DataKind getDataKind() const override;
105106 PDB_SymType getSymTag() const override;
106107 PDB_UniqueId getGuid() const override;
3030
3131 uint64_t getLoadAddress() const override;
3232 void setLoadAddress(uint64_t Address) override;
33 std::unique_ptr getGlobalScope() override;
33 std::unique_ptr getGlobalScope() const override;
3434 std::unique_ptr getSymbolById(uint32_t SymbolId) const override;
3535
3636 std::unique_ptr
1919 class raw_ostream;
2020
2121 namespace pdb {
22
23 class PDBSymbolTypeVTable;
24 class PDBSymbolTypeVTableShape;
2225
2326 /// IPDBRawSymbol defines an interface used to represent an arbitrary symbol.
2427 /// It exposes a monolithic interface consisting of accessors for the union of
109112 virtual Variant getValue() const = 0;
110113 virtual uint32_t getVirtualBaseDispIndex() const = 0;
111114 virtual uint32_t getVirtualBaseOffset() const = 0;
115 virtual std::unique_ptr
116 getVirtualBaseTableType() const = 0;
112117 virtual uint32_t getVirtualTableShapeId() const = 0;
113118 virtual PDB_DataKind getDataKind() const = 0;
114119 virtual PDB_SymType getSymTag() const = 0;
2828
2929 virtual uint64_t getLoadAddress() const = 0;
3030 virtual void setLoadAddress(uint64_t Address) = 0;
31 virtual std::unique_ptr getGlobalScope() = 0;
31 virtual std::unique_ptr getGlobalScope() const = 0;
3232 virtual std::unique_ptr getSymbolById(uint32_t SymbolId) const = 0;
3333
3434 template
3535 std::unique_ptr getConcreteSymbolById(uint32_t SymbolId) const {
36 auto Symbol(getSymbolById(SymbolId));
37 if (!Symbol)
38 return nullptr;
39
40 T *ConcreteSymbol = dyn_cast(Symbol.get());
41 if (!ConcreteSymbol)
42 return nullptr;
43 (void)Symbol.release();
44 return std::unique_ptr(ConcreteSymbol);
36 return unique_dyn_cast_or_null(getSymbolById(SymbolId));
4537 }
4638
4739 virtual std::unique_ptr
100100 uint32_t getVirtualBaseDispIndex() const override;
101101 uint32_t getVirtualBaseOffset() const override;
102102 uint32_t getVirtualTableShapeId() const override;
103 std::unique_ptr getVirtualBaseTableType() const override;
103104 PDB_DataKind getDataKind() const override;
104105 PDB_SymType getSymTag() const override;
105106 PDB_UniqueId getGuid() const override;
3131
3232 uint64_t getLoadAddress() const override;
3333 void setLoadAddress(uint64_t Address) override;
34 std::unique_ptr getGlobalScope() override;
34 std::unique_ptr getGlobalScope() const override;
3535 std::unique_ptr getSymbolById(uint32_t SymbolId) const override;
3636
3737 std::unique_ptr
6161 protected:
6262 PDBSymbol(const IPDBSession &PDBSession,
6363 std::unique_ptr Symbol);
64 PDBSymbol(PDBSymbol &Symbol);
6465
6566 public:
6667 static std::unique_ptr
8889 template std::unique_ptr findOneChild() const {
8990 auto Enumerator(findAllChildren());
9091 return Enumerator->getNext();
91 }
92
93 template T *cast() { return llvm::dyn_cast(this); }
94
95 template const T *cast() const {
96 return llvm::dyn_cast(this);
9792 }
9893
9994 std::unique_ptr clone() const;
127122
128123 template
129124 std::unique_ptr getConcreteSymbolByIdHelper(uint32_t Id) const {
130 auto Sym = getSymbolByIdHelper(Id);
131 if (!Sym)
132 return nullptr;
133 ConcreteType *Result = Sym->cast();
134 if (!Result)
135 return nullptr;
136 Sym.release();
137 return std::unique_ptr(Result);
125 return unique_dyn_cast_or_null(getSymbolByIdHelper(Id));
138126 }
139127
140128 const IPDBSession &Session;
141 const std::unique_ptr RawSymbol;
129 std::unique_ptr RawSymbol;
142130 };
143131
144132 } // namespace llvm
3636 FORWARD_SYMBOL_METHOD(getSignature)
3737 FORWARD_SYMBOL_METHOD(getSymbolsFileName)
3838
39 uint32_t getPointerByteSize() const;
40
3941 private:
4042 void dumpChildren(raw_ostream &OS, StringRef Label, PDB_SymType ChildType,
4143 int Indent) const;
1111
1212 #include "PDBSymbol.h"
1313 #include "PDBTypes.h"
14
15 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
16 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
1417
1518 namespace llvm {
1619
99 #ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H
1010 #define LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H
1111
12 #include "IPDBSession.h"
1213 #include "PDBSymbol.h"
14 #include "PDBSymbolTypeBaseClass.h"
1315 #include "PDBTypes.h"
1416
1517 namespace llvm {
1719 class raw_ostream;
1820
1921 namespace pdb {
22
2023 class PDBSymbolTypeUDT : public PDBSymbol {
2124 public:
2225 PDBSymbolTypeUDT(const IPDBSession &PDBSession,
2326 std::unique_ptr UDTSymbol);
27
28 std::unique_ptr clone() const {
29 return getSession().getConcreteSymbolById(
30 getSymIndexId());
31 }
2432
2533 DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::UDT)
2634
2727 void dump(PDBSymDumper &Dumper) const override;
2828
2929 FORWARD_SYMBOL_ID_METHOD(getClassParent)
30 FORWARD_SYMBOL_METHOD(getOffset)
3031 FORWARD_SYMBOL_METHOD(isConstType)
3132 FORWARD_SYMBOL_ID_METHOD(getLexicalParent)
3233 FORWARD_SYMBOL_ID_METHOD(getType)
0 //===- UDTLayout.h - UDT layout info ----------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_PDB_UDTLAYOUT_H
10 #define LLVM_DEBUGINFO_PDB_UDTLAYOUT_H
11
12 #include "PDBSymbol.h"
13 #include "PDBTypes.h"
14
15 #include "llvm/ADT/ArrayRef.h"
16 #include "llvm/ADT/BitVector.h"
17
18 #include
19 #include
20
21 namespace llvm {
22
23 class raw_ostream;
24
25 namespace pdb {
26
27 class PDBSymTypeBaseClass;
28 class PDBSymbolData;
29 class PDBSymbolTypeUDT;
30 class PDBSymbolTypeVTable;
31
32 class ClassLayout;
33 class BaseClassLayout;
34 class StorageItemBase;
35 class UDTLayoutBase;
36
37 class StorageItemBase {
38 public:
39 StorageItemBase(const UDTLayoutBase &Parent, const PDBSymbol &Symbol,
40 const std::string &Name, uint32_t OffsetInParent,
41 uint32_t Size);
42 virtual ~StorageItemBase() {}
43
44 virtual uint32_t deepPaddingSize() const;
45
46 const UDTLayoutBase &getParent() const { return Parent; }
47 StringRef getName() const { return Name; }
48 uint32_t getOffsetInParent() const { return OffsetInParent; }
49 uint32_t getSize() const { return SizeOf; }
50 const PDBSymbol &getSymbol() const { return Symbol; }
51
52 protected:
53 const UDTLayoutBase &Parent;
54 const PDBSymbol &Symbol;
55 BitVector UsedBytes;
56 std::string Name;
57 uint32_t OffsetInParent = 0;
58 uint32_t SizeOf = 0;
59 };
60
61 class DataMemberLayoutItem : public StorageItemBase {
62 public:
63 DataMemberLayoutItem(const UDTLayoutBase &Parent,
64 std::unique_ptr DataMember);
65
66 virtual uint32_t deepPaddingSize() const;
67
68 const PDBSymbolData &getDataMember();
69
70 private:
71 std::unique_ptr DataMember;
72 std::unique_ptr UdtLayout;
73 };
74
75 class VTableLayoutItem : public StorageItemBase {
76 public:
77 VTableLayoutItem(const UDTLayoutBase &Parent,
78 std::unique_ptr VTable);
79
80 private:
81 std::unique_ptr VTable;
82 std::vector> VTableFuncs;
83 };
84
85 class UDTLayoutBase {
86 public:
87 UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name,
88 uint32_t Size);
89
90 uint32_t shallowPaddingSize() const;
91 uint32_t deepPaddingSize() const;
92
93 const BitVector &usedBytes() const { return UsedBytes; }
94
95 uint32_t getClassSize() const { return SizeOf; }
96
97 const PDBSymbol &getSymbol() const { return Symbol; }
98
99 ArrayRef> layout_items() const {
100 return ChildStorage;
101 }
102
103 ArrayRef> other_items() const {
104 return NonStorageItems;
105 }
106
107 protected:
108 void initializeChildren(const PDBSymbol &Sym);
109
110 void addChildToLayout(std::unique_ptr Child);
111
112 uint32_t SizeOf = 0;
113 std::string Name;
114
115 const PDBSymbol &Symbol;
116 BitVector UsedBytes;
117 std::vector> NonStorageItems;
118 std::vector> ChildStorage;
119 std::vector> ChildrenPerByte;
120 std::vector BaseClasses;
121 VTableLayoutItem *VTable = nullptr;
122 };
123
124 class ClassLayout : public UDTLayoutBase {
125 public:
126 explicit ClassLayout(std::unique_ptr UDT);
127
128 private:
129 std::unique_ptr Type;
130 };
131
132 class BaseClassLayout : public UDTLayoutBase, public StorageItemBase {
133 public:
134 BaseClassLayout(const UDTLayoutBase &Parent,
135 std::unique_ptr Base);
136
137 private:
138 std::unique_ptr Base;
139 bool IsVirtualBase;
140 };
141 }
142 } // namespace llvm
143
144 #endif // LLVM_DEBUGINFO_PDB_UDTLAYOUT_H
383383 -> decltype(cast(Val)) {
384384 if (!Val)
385385 return nullptr;
386 return unique_dyn_cast(Val);
386 return unique_dyn_cast(Val);
387387 }
388388
389389 template
100100 PDBSymbolUnknown.cpp
101101 PDBSymbolUsingNamespace.cpp
102102 PDBSymDumper.cpp
103 UDTLayout.cpp
103104 ${PDB_IMPL_SOURCES}
104105
105106 ADDITIONAL_HEADER_DIRS
1313 #include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h"
1414 #include "llvm/DebugInfo/PDB/DIA/DIASession.h"
1515 #include "llvm/DebugInfo/PDB/PDBExtras.h"
16 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
17 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
18 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
1619 #include "llvm/Support/ConvertUTF.h"
1720 #include "llvm/Support/raw_ostream.h"
1821
716719 return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualTableShapeId);
717720 }
718721
722 std::unique_ptr
723 DIARawSymbol::getVirtualBaseTableType() const {
724 CComPtr TableType;
725 if (FAILED(Symbol->get_virtualBaseTableType(&TableType)) || !TableType)
726 return nullptr;
727
728 auto RawVT = llvm::make_unique(Session, TableType);
729 auto Pointer =
730 llvm::make_unique(Session, std::move(RawVT));
731 return unique_dyn_cast(Pointer->getPointeeType());
732 }
733
719734 PDB_DataKind DIARawSymbol::getDataKind() const {
720735 return PrivateGetDIAValue(Symbol,
721736 &IDiaSymbol::get_dataKind);
139139 Session->put_loadAddress(Address);
140140 }
141141
142 std::unique_ptr DIASession::getGlobalScope() {
142 std::unique_ptr DIASession::getGlobalScope() const {
143143 CComPtr GlobalScope;
144144 if (S_OK != Session->get_globalScope(&GlobalScope))
145145 return nullptr;
1212 #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
1313 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
1414 #include "llvm/DebugInfo/PDB/PDBExtras.h"
15 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
16 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
1517 #include "llvm/Support/ConvertUTF.h"
1618 #include "llvm/Support/raw_ostream.h"
1719
317319 return 0;
318320 }
319321
322 std::unique_ptr
323 NativeRawSymbol::getVirtualBaseTableType() const {
324 return nullptr;
325 }
326
320327 PDB_DataKind NativeRawSymbol::getDataKind() const {
321328 return PDB_DataKind::Unknown;
322329 }
6969
7070 void NativeSession::setLoadAddress(uint64_t Address) {}
7171
72 std::unique_ptr NativeSession::getGlobalScope() {
73 auto RawSymbol = llvm::make_unique(*this);
72 std::unique_ptr NativeSession::getGlobalScope() const {
73 auto RawSymbol =
74 llvm::make_unique(const_cast(*this));
7475 auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol)));
7576 std::unique_ptr ExeSymbol(
7677 static_cast(PdbSymbol.release()));
5353 std::unique_ptr Symbol)
5454 : Session(PDBSession), RawSymbol(std::move(Symbol)) {}
5555
56 PDBSymbol::PDBSymbol(PDBSymbol &Symbol)
57 : Session(Symbol.Session), RawSymbol(std::move(Symbol.RawSymbol)) {}
58
5659 PDBSymbol::~PDBSymbol() = default;
5760
5861 #define FACTORY_SYMTAG_CASE(Tag, Type) \
98101 new PDBSymbolUnknown(PDBSession, std::move(Symbol)));
99102 }
100103 }
101
102 #define TRY_DUMP_TYPE(Type) \
103 if (const Type *DerivedThis = this->cast()) \
104 Dumper.dump(OS, Indent, *DerivedThis);
105
106 #define ELSE_TRY_DUMP_TYPE(Type, Dumper) else TRY_DUMP_TYPE(Type, Dumper)
107104
108105 void PDBSymbol::defaultDump(raw_ostream &OS, int Indent) const {
109106 RawSymbol->dump(OS, Indent);
99 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
1010
1111 #include "llvm/DebugInfo/PDB/PDBSymDumper.h"
12 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
1213
1314 #include
1415
2223 }
2324
2425 void PDBSymbolExe::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
26
27 uint32_t PDBSymbolExe::getPointerByteSize() const {
28 auto Pointer = findOneChild();
29 if (Pointer)
30 return Pointer->getLength();
31
32 if (getMachineType() == PDB_Machine::x86)
33 return 4;
34 return 8;
35 }
88
99 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
1010
11 #include "llvm/DebugInfo/PDB/IPDBSession.h"
1112 #include "llvm/DebugInfo/PDB/PDBSymDumper.h"
13 #include "llvm/DebugInfo/PDB/PDBSymbol.h"
14 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
15 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
16 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
17 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
18 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
19 #include "llvm/DebugInfo/PDB/UDTLayout.h"
1220
1321 #include
1422
0 //===- UDTLayout.cpp --------------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/PDB/UDTLayout.h"
10
11 #include "llvm/DebugInfo/PDB/IPDBSession.h"
12 #include "llvm/DebugInfo/PDB/PDBSymbol.h"
13 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
14 #include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
15 #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
16 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
17 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
18 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
19 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
20
21 #include
22
23 using namespace llvm;
24 using namespace llvm::pdb;
25
26 static std::unique_ptr getSymbolType(const PDBSymbol &Symbol) {
27 const IPDBSession &Session = Symbol.getSession();
28 const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol();
29 uint32_t TypeId = RawSymbol.getTypeId();
30 return Session.getSymbolById(TypeId);
31 }
32
33 static uint32_t getTypeLength(const PDBSymbol &Symbol) {
34 auto SymbolType = getSymbolType(Symbol);
35 const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
36
37 return RawType.getLength();
38 }
39
40 StorageItemBase::StorageItemBase(const UDTLayoutBase &Parent,
41 const PDBSymbol &Symbol,
42 const std::string &Name,
43 uint32_t OffsetInParent, uint32_t Size)
44 : Parent(Parent), Symbol(Symbol), Name(Name), SizeOf(Size),
45 OffsetInParent(OffsetInParent) {
46 UsedBytes.resize(SizeOf, true);
47 }
48
49 uint32_t StorageItemBase::deepPaddingSize() const {
50 // sizeof(Field) - sizeof(typeof(Field)) is trailing padding.
51 return SizeOf - getTypeLength(Symbol);
52 }
53
54 DataMemberLayoutItem::DataMemberLayoutItem(
55 const UDTLayoutBase &Parent, std::unique_ptr DataMember)
56 : StorageItemBase(Parent, *DataMember, DataMember->getName(),
57 DataMember->getOffset(), getTypeLength(*DataMember)),
58 DataMember(std::move(DataMember)) {
59 auto Type = this->DataMember->getType();
60 if (auto UDT = unique_dyn_cast(Type)) {
61 // UDT data members might have padding in between fields, but otherwise
62 // a member should occupy its entire storage.
63 UsedBytes.resize(SizeOf, false);
64 UdtLayout = llvm::make_unique(std::move(UDT));
65 }
66 }
67
68 const PDBSymbolData &DataMemberLayoutItem::getDataMember() {
69 return *dyn_cast(&Symbol);
70 }
71
72 uint32_t DataMemberLayoutItem::deepPaddingSize() const {
73 uint32_t Result = StorageItemBase::deepPaddingSize();
74 if (UdtLayout)
75 Result += UdtLayout->deepPaddingSize();
76 return Result;
77 }
78
79 VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,
80 std::unique_ptr VTable)
81 : StorageItemBase(Parent, *VTable, "", 0, getTypeLength(*VTable)),
82 VTable(std::move(VTable)) {
83 // initialize vtbl methods.
84 auto VTableType = cast(this->VTable->getType());
85 uint32_t PointerSize = VTableType->getLength();
86
87 if (auto Shape = unique_dyn_cast(
88 VTableType->getPointeeType())) {
89 VTableFuncs.resize(Shape->getCount());
90
91 auto ParentFunctions = Parent.getSymbol().findAllChildren();
92 while (auto Func = ParentFunctions->getNext()) {
93 if (Func->isVirtual()) {
94 uint32_t Index = Func->getVirtualBaseOffset();
95 assert(Index % PointerSize == 0);
96 Index /= PointerSize;
97
98 // Don't allow a compiler generated function to overwrite a user
99 // function in the VTable. Not sure why this happens, but a function
100 // named __vecDelDtor sometimes shows up on top of the destructor.
101 if (Func->isCompilerGenerated() && VTableFuncs[Index])
102 continue;
103 VTableFuncs[Index] = std::move(Func);
104 }
105 }
106 }
107 }
108
109 UDTLayoutBase::UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name,
110 uint32_t Size)
111 : Symbol(Symbol), Name(Name), SizeOf(Size) {
112 UsedBytes.resize(Size);
113 ChildrenPerByte.resize(Size);
114 initializeChildren(Symbol);
115 }
116
117 ClassLayout::ClassLayout(std::unique_ptr UDT)
118 : UDTLayoutBase(*UDT, UDT->getName(), UDT->getLength()),
119 Type(std::move(UDT)) {}
120
121 BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent,
122 std::unique_ptr Base)
123 : UDTLayoutBase(*Base, Base->getName(), Base->getLength()),
124 StorageItemBase(Parent, *Base, Base->getName(), Base->getOffset(),
125 Base->getLength()),
126 Base(std::move(Base)) {
127 IsVirtualBase = this->Base->isVirtualBaseClass();
128 }
129
130 uint32_t UDTLayoutBase::shallowPaddingSize() const {
131 return UsedBytes.size() - UsedBytes.count();
132 }
133
134 uint32_t UDTLayoutBase::deepPaddingSize() const {
135 uint32_t Result = shallowPaddingSize();
136 for (auto &Child : ChildStorage)
137 Result += Child->deepPaddingSize();
138 return Result;
139 }
140
141 void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) {
142 auto Children = Sym.findAllChildren();
143 while (auto Child = Children->getNext()) {
144 if (auto Data = unique_dyn_cast(Child)) {
145 if (Data->getDataKind() == PDB_DataKind::Member) {
146 auto DM =
147 llvm::make_unique(*this, std::move(Data));
148
149 addChildToLayout(std::move(DM));
150 } else {
151 NonStorageItems.push_back(std::move(Data));
152 }
153 continue;
154 }
155
156 if (auto Base = unique_dyn_cast(Child)) {
157 auto BL = llvm::make_unique(*this, std::move(Base));
158 BaseClasses.push_back(BL.get());
159
160 addChildToLayout(std::move(BL));
161 continue;
162 }
163
164 if (auto VT = unique_dyn_cast(Child)) {
165 auto VTLayout = llvm::make_unique(*this, std::move(VT));
166
167 VTable = VTLayout.get();
168
169 addChildToLayout(std::move(VTLayout));
170 continue;
171 }
172
173 NonStorageItems.push_back(std::move(Child));
174 }
175 }
176
177 void UDTLayoutBase::addChildToLayout(std::unique_ptr Child) {
178 uint32_t Begin = Child->getOffsetInParent();
179 uint32_t End = Begin + Child->getSize();
180 UsedBytes.set(Begin, End);
181 while (Begin != End) {
182 ChildrenPerByte[Begin].push_back(Child.get());
183 ++Begin;
184 }
185
186 auto Loc = std::upper_bound(
187 ChildStorage.begin(), ChildStorage.end(), Begin,
188 [](uint32_t Off, const std::unique_ptr &Item) {
189 return Off < Item->getOffsetInParent();
190 });
191
192 ChildStorage.insert(Loc, std::move(Child));
193 }
3131 ; TYPES_FORMAT-DAG: typedef class A ClassAType
3232
3333 ; TYPES_1: Classes
34 ; TYPES_1: struct A {
34 ; TYPES_1: struct A [sizeof = 4] {
3535 ; TYPES_1: virtual void PureFunc() = 0
3636 ; TYPES_1: virtual void VirtualFunc()
3737 ; TYPES_1: void RegularFunc()
3838 ; TYPES_1: }
3939
4040 ; TYPES_2: Classes
41 ; TYPES_2: struct MemberTest {
41 ; TYPES_2: struct MemberTest [sizeof = 96] {
4242 ; TYPES_2: data +0x00 [sizeof=4] MemberTest::NestedEnum m_nested_enum
4343 ; TYPES_2: data +0x04 [sizeof=4] int m_typedef
4444 ; TYPES_2: data +0x08 [sizeof=1] bool m_bool
0 // Compile with "cl /c /Zi /GR- SimplePaddingTest.cpp"
1 // Link with "link SimplePaddingTest.obj /debug /nodefaultlib /entry:main"
2
3 #include
4
5 extern "C" using at_exit_handler = void();
6
7 int atexit(at_exit_handler handler) { return 0; }
8
9 struct SimplePadNoPadding {
10 int32_t X;
11 int32_t Y;
12 // No padding anywhere, sizeof(T) = 8
13 } A;
14
15 struct SimplePadUnion {
16 union {
17 int32_t X;
18 int64_t Y;
19 struct {
20 int32_t X;
21 // 4 bytes of padding here
22 int64_t Y;
23 } Z;
24 };
25 // Since the padding occurs at a location that is occupied by other storage
26 // (namely the Y member), the storage will still be considered used, and so
27 // there will be no unused bytes in the larger class. But in the debug
28 // info for the nested struct, we should see padding.
29 // sizeof(SimplePadUnion) == sizeof(Z) == 16
30 } B;
31
32 struct SimplePadNoPadding2 {
33 bool A;
34 bool B;
35 bool C;
36 bool D;
37 // No padding anywhere, sizeof(T) = 4
38 } C;
39
40 struct alignas(4) SimplePadFields1 {
41 char A;
42 char B;
43 char C;
44 // 1 byte of padding here, sizeof(T) = 4
45 } E;
46
47 struct SimplePadFields2 {
48 int32_t Y;
49 char X;
50 } F;
51
52 struct SimplePadBase {
53 // Make sure this class is 4 bytes, and the derived class requires 8 byte
54 // alignment, so that padding is inserted between base and derived.
55 int32_t X;
56 // No padding here
57 } G;
58
59 struct SimplePadDerived : public SimplePadBase {
60 // 4 bytes of padding here due to Y requiring 8 byte alignment.
61 // Thus, sizeof(T) = 16
62 int64_t Y;
63 } H;
64
65 struct SimplePadEmptyBase1 {};
66 struct SimplePadEmptyBase2 {};
67
68 struct SimplePadEmpty : public SimplePadEmptyBase1, SimplePadEmptyBase2 {
69 // Bases have to occupy at least 1 byte of storage, so this requires
70 // 2 bytes of padding, plus 1 byte for each base, yielding sizeof(T) = 8
71 int32_t X;
72 } I;
73
74 struct SimplePadVfptr {
75 virtual ~SimplePadVfptr() {}
76 static void operator delete(void *ptr, size_t sz) {}
77 int32_t X;
78 } J;
79
80 struct NonEmptyBase1 {
81 bool X;
82 };
83
84 struct NonEmptyBase2 {
85 bool Y;
86 };
87
88 struct SimplePadMultiInherit : public NonEmptyBase1, public NonEmptyBase2 {
89 // X and Y from the 2 bases will get squished together, leaving 2 bytes
90 // of padding necessary for proper alignment of an int32.
91 // Therefore, sizeof(T) = 2 + 2 + 4 = 8
92 int32_t X;
93 } K;
94
95 struct SimplePadMultiInherit2 : public SimplePadFields1, SimplePadFields2 {
96 // There should be 1 byte of padding after the first class, and
97 // 3 bytes of padding after the second class.
98 int32_t X;
99 } L;
100
101 struct OneLevelInherit : public NonEmptyBase1 {
102 short Y;
103 };
104
105 struct SimplePadTwoLevelInherit : public OneLevelInherit {
106 // OneLevelInherit has nested padding because of its base,
107 // and then padding again because of this class. So each
108 // class should be 4 bytes, yielding sizeof(T) = 12.
109 int64_t Z;
110 } M;
111
112 struct SimplePadAggregate {
113 NonEmptyBase1 X;
114 int32_t Y;
115 // the presence of X will cause 3 bytes of padding to be injected.
116 } N;
117
118 int main(int argc, char **argv) {
119
120 return 0;
121 }
1313 ; GLOBALS_TEST-DAG: GlobalsTest::Enum GlobalsTest::EnumVar
1414
1515 ; MEMBERS_TEST: ---TYPES---
16 ; MEMBERS_TEST: class MembersTest::A {
16 ; MEMBERS_TEST: class MembersTest::A [sizeof = 16] {
1717 ; MEMBERS_TEST-DAG: typedef int NestedTypedef
1818 ; MEMBERS_TEST-DAG: enum NestedEnum
1919 ; MEMBERS_TEST: void MemberFunc()
20 ; MEMBERS_TEST-DAG: int IntMemberVar
21 ; MEMBERS_TEST-DAG: double DoubleMemberVar
20 ; MEMBERS_TEST-DAG: data +0x00 [sizeof=4] int IntMemberVar
21 ; MEMBERS_TEST-NEXT: (4 bytes)
22 ; MEMBERS_TEST-NEXT: data +0x08 [sizeof=8] double DoubleMemberVar
2223 ; MEMBERS_TEST: }
2324
2425 ; BASE_CLASS_A: ---TYPES---
25 ; BASE_CLASS_A: class BaseClassTest::A {}
26 ; BASE_CLASS_A: class BaseClassTest::A [sizeof = 1] {}
2627
2728 ; BASE_CLASS_B: ---TYPES---
28 ; BASE_CLASS_B: class BaseClassTest::B
29 ; BASE_CLASS_B: class BaseClassTest::B [sizeof = 4]
2930 ; BASE_CLASS_B-NEXT: : public virtual BaseClassTest::A {
3031
3132 ; BASE_CLASS_C: ---TYPES---
32 ; BASE_CLASS_C: class BaseClassTest::C
33 ; BASE_CLASS_C: class BaseClassTest::C [sizeof = 4]
3334 ; BASE_CLASS_C-NEXT: : public virtual BaseClassTest::A {
3435
3536 ; BASE_CLASS_D: ---TYPES---
36 ; BASE_CLASS_D: class BaseClassTest::D
37 ; BASE_CLASS_D: class BaseClassTest::D [sizeof = 8]
3738 ; BASE_CLASS_D-DAG: protected BaseClassTest::B
3839 ; BASE_CLASS_D-DAG: private BaseClassTest::C
3940 ; BASE_CLASS_D-DAG: protected virtual BaseClassTest::A
4041
4142 ; UDT_KIND_TEST: ---TYPES---
42 ; UDT_KIND_TEST-DAG: union UdtKindTest::C {}
43 ; UDT_KIND_TEST-DAG: class UdtKindTest::B {}
44 ; UDT_KIND_TEST-DAG: struct UdtKindTest::A {}
43 ; UDT_KIND_TEST-DAG: union UdtKindTest::C [sizeof = 1] {}
44 ; UDT_KIND_TEST-DAG: class UdtKindTest::B [sizeof = 1] {}
45 ; UDT_KIND_TEST-DAG: struct UdtKindTest::A [sizeof = 1] {}
4546
4647 ; BITFIELD_TEST: ---TYPES---
47 ; BITFIELD_TEST: struct BitFieldTest::A {
48 ; BITFIELD_TEST: struct BitFieldTest::A [sizeof = 8] {
4849 ; BITFIELD_TEST-NEXT: +0x00 [sizeof=4] int Bits1 : 1
4950 ; BITFIELD_TEST-NEXT: +0x00 [sizeof=4] int Bits2 : 2
5051 ; BITFIELD_TEST-NEXT: +0x00 [sizeof=4] int Bits3 : 3
99
1010 ; MEMBER_ENUM: ---TYPES---
1111 ; MEMBER_ENUM: Classes:
12 ; MEMBER_ENUM: struct __vc_attributes::threadingAttribute {
12 ; MEMBER_ENUM: struct __vc_attributes::threadingAttribute [sizeof = 4] {
1313 ; MEMBER_ENUM-NEXT: enum threading_e {
1414 ; MEMBER_ENUM-NEXT: apartment = 1
1515 ; MEMBER_ENUM-NEXT: single = 2
0 ; RUN: llvm-pdbdump pretty -classes -class-definitions=layout \
1 ; RUN: -include-types=SimplePad %p/Inputs/SimplePaddingTest.pdb > %t
2
3 ; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PADDING
4 ; RUN: FileCheck -input-file=%t %s -check-prefix=UNION
5 ; RUN: FileCheck -input-file=%t %s -check-prefix=NESTED_UNION
6 ; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS1
7 ; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS2
8 ; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PAD_IN_BASE
9 ; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_IN_DERIVED
10 ; RUN: FileCheck -input-file=%t %s -check-prefix=EMPTY_BASE
11 ; RUN: FileCheck -input-file=%t %s -check-prefix=VFPTR
12 ; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT
13 ; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT2
14 ; RUN: FileCheck -input-file=%t %s -check-prefix=DEEP_INHERIT
15 ; RUN: FileCheck -input-file=%t %s -check-prefix=AGGREGATE
16
17 ; NO_PADDING: struct SimplePadNoPadding [sizeof = 8] {
18 ; NO_PADDING-NEXT: data +0x00 [sizeof=4] int X
19 ; NO_PADDING-NEXT: data +0x04 [sizeof=4] int Y
20 ; NO_PADDING-NEXT: }
21
22 ; UNION: struct SimplePadUnion [sizeof = 16] {
23 ; UNION-NEXT: data +0x00 [sizeof=4] int X
24 ; UNION-NEXT: data +0x00 [sizeof=8] __int64 Y
25 ; UNION-NEXT: data +0x00 [sizeof=16] SimplePadUnion::
26 ; UNION-NEXT: }
27
28 ; NESTED_UNION: struct {{SimplePadUnion::.*}} [sizeof = 16] {
29 ; NESTED_UNION-NEXT: data +0x00 [sizeof=4] int X
30 ; NESTED_UNION-NEXT: (4 bytes)
31 ; NESTED_UNION-NEXT: data +0x08 [sizeof=8] __int64 Y
32 ; NESTED_UNION-NEXT: }
33
34 ; PAD_FROM_FIELDS1: struct SimplePadFields1 [sizeof = 4] {
35 ; PAD_FROM_FIELDS1-NEXT: data +0x00 [sizeof=1] char A
36 ; PAD_FROM_FIELDS1-NEXT: data +0x01 [sizeof=1] char B
37 ; PAD_FROM_FIELDS1-NEXT: data +0x02 [sizeof=1] char C
38 ; PAD_FROM_FIELDS1-NEXT: (1 bytes)
39 ; PAD_FROM_FIELDS1-NEXT: }
40
41 ; PAD_FROM_FIELDS2: struct SimplePadFields2 [sizeof = 8] {
42 ; PAD_FROM_FIELDS2-NEXT: data +0x00 [sizeof=4] int Y
43 ; PAD_FROM_FIELDS2-NEXT: data +0x04 [sizeof=1] char X
44 ; PAD_FROM_FIELDS2-NEXT: (3 bytes)
45 ; PAD_FROM_FIELDS2-NEXT: }
46
47 ; NO_PAD_IN_BASE: struct SimplePadBase [sizeof = 4] {
48 ; NO_PAD_IN_BASE-NEXT: data +0x00 [sizeof=4] int X
49 ; NO_PAD_IN_BASE-NEXT: }
50
51 ; PAD_IN_DERIVED: struct SimplePadDerived [sizeof = 16]
52 ; PAD_IN_DERIVED-NEXT: public SimplePadBase {
53 ; PAD_IN_DERIVED-NEXT: (4 bytes)
54 ; PAD_IN_DERIVED-NEXT: data +0x08 [sizeof=8] __int64 Y
55 ; PAD_IN_DERIVED-NEXT: }
56
57 ; EMPTY_BASE: struct SimplePadEmpty [sizeof = 8]
58 ; EMPTY_BASE-NEXT: : public SimplePadEmptyBase1
59 ; EMPTY_BASE-NEXT: , public SimplePadEmptyBase2 {
60 ; EMPTY_BASE-NEXT: (2 bytes)
61 ; EMPTY_BASE-NEXT: data +0x04 [sizeof=4] int X
62 ; EMPTY_BASE-NEXT: }
63
64 ; VFPTR: struct SimplePadVfptr [sizeof = 8] {
65 ; VFPTR-NEXT: data +0x00 [sizeof=4] __vfptr
66 ; VFPTR-NEXT: data +0x04 [sizeof=4] int X
67 ; VFPTR-NEXT: }
68
69 ; MULTIPLE_INHERIT: struct SimplePadMultiInherit [sizeof = 8]
70 ; MULTIPLE_INHERIT-NEXT: : public NonEmptyBase1
71 ; MULTIPLE_INHERIT-NEXT: , public NonEmptyBase2 {
72 ; MULTIPLE_INHERIT-NEXT: (2 bytes)
73 ; MULTIPLE_INHERIT-NEXT: data +0x04 [sizeof=4] int X
74 ; MULTIPLE_INHERIT-NEXT: }
75
76 ; MULTIPLE_INHERIT2: SimplePadMultiInherit2 [sizeof = 16]
77 ; MULTIPLE_INHERIT2-NEXT: : public SimplePadFields1
78 ; MULTIPLE_INHERIT2-NEXT: , public SimplePadFields2 {
79 ; MULTIPLE_INHERIT2-NEXT: data +0x0c [sizeof=4] int X
80 ; MULTIPLE_INHERIT2-NEXT: }
81
82 ; DEEP_INHERIT: struct SimplePadTwoLevelInherit [sizeof = 16]
83 ; DEEP_INHERIT-NEXT: : public OneLevelInherit {
84 ; DEEP_INHERIT-NEXT: (4 bytes)
85 ; DEEP_INHERIT-NEXT: data +0x08 [sizeof=8] __int64 Z
86 ; DEEP_INHERIT-NEXT: }
87
88
89 ; AGGREGATE: struct SimplePadAggregate [sizeof = 8] {
90 ; AGGREGATE-NEXT: data +0x00 [sizeof=1] NonEmptyBase1 X
91 ; AGGREGATE-NEXT: (3 bytes)
92 ; AGGREGATE-NEXT: data +0x04 [sizeof=4] int Y
93 ; AGGREGATE-NEXT: }
2727 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
2828 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
2929 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
30 #include "llvm/Support/Compiler.h"
30 #include "llvm/DebugInfo/PDB/UDTLayout.h"
31
3132 #include "llvm/Support/Format.h"
3233
3334 using namespace llvm;
3637 ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
3738 : PDBSymDumper(true), Printer(P) {}
3839
39 static void analyzePadding(const PDBSymbolTypeUDT &Class, BitVector &Padding,
40 uint32_t &FirstFieldOffset) {
41 Padding.resize(Class.getLength(), true);
42 auto Children = Class.findAllChildren();
43 bool IsFirst = true;
44 FirstFieldOffset = Class.getLength();
45
46 while (auto Data = Children->getNext()) {
47 // Ignore data members which are not relative to this. Usually these are
48 // static data members or constexpr and occupy no space. We also need to
49 // handle BitFields since the PDB doesn't consider them ThisRel, but they
50 // still occupy space in the record layout.
51 auto LocType = Data->getLocationType();
52 if (LocType != PDB_LocType::ThisRel && LocType != PDB_LocType::BitField)
53 continue;
54
55 uint64_t Start = Data->getOffset();
56 if (IsFirst) {
57 FirstFieldOffset = Start;
58 IsFirst = false;
59 }
60
61 auto VarType = Data->getType();
62 uint64_t Size = VarType->getRawSymbol().getLength();
63 Padding.reset(Start, Start + Size);
64 }
65
66 // Unmark anything that comes before the first field so it doesn't get
67 // counted as padding. In reality this is going to be vptrs or base class
68 // members, but we don't correctly handle that yet.
69 // FIXME: Handle it.
70 Padding.reset(0, FirstFieldOffset);
71 }
72
7340 void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
7441 assert(opts::pretty::ClassFormat !=
7542 opts::pretty::ClassDefinitionFormat::None);
7643
7744 uint32_t Size = Class.getLength();
78 uint32_t FirstFieldOffset = 0;
79 BitVector Padding;
80 analyzePadding(Class, Padding, FirstFieldOffset);
8145
82 if (opts::pretty::OnlyPaddingClasses && (Padding.count() == 0))
46 ClassLayout Layout(Class.clone());
47
48 if (opts::pretty::OnlyPaddingClasses && (Layout.shallowPaddingSize() == 0))
8349 return;
8450
85 Printer.NewLine();
86 WithColor(Printer, PDB_ColorItem::Comment).get() << "// sizeof = " << Size;
8751 Printer.NewLine();
8852
8953 WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
9054 WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
55 WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size
56 << "]";
9157
9258 auto Bases = Class.findAllChildren();
9359 if (Bases->getChildCount() > 0) {
11076 }
11177
11278 Printer << " {";
113 auto Children = Class.findAllChildren();
11479 Printer.Indent();
115 int DumpedCount = 0;
11680
117 int NextPaddingByte = Padding.find_first();
118 while (auto Child = Children->getNext()) {
119 if (auto Data = llvm::dyn_cast(Child.get())) {
120 if (Data->getDataKind() == PDB_DataKind::Member && NextPaddingByte >= 0) {
121 // If there are padding bytes remaining, see if this field is the first
122 // to cross a padding boundary, and print a padding field indicator if
123 // so.
124 int Off = Data->getOffset();
125 if (Off > NextPaddingByte) {
126 uint32_t Amount = Off - NextPaddingByte;
127 Printer.NewLine();
128 WithColor(Printer, PDB_ColorItem::Padding).get()
129 << " (" << Amount << " bytes)";
130 assert(Padding.find_next_unset(NextPaddingByte) == Off);
131 NextPaddingByte = Padding.find_next(Off);
132 }
81 // Dump non-layout items first, but only if we're not in layout-only mode.
82 if (opts::pretty::ClassFormat !=
83 opts::pretty::ClassDefinitionFormat::Layout) {
84 for (auto &Other : Layout.other_items())
85 Other->dump(*this);
86 }
87
88 const BitVector &UseMap = Layout.usedBytes();
89 int NextUnusedByte = Layout.usedBytes().find_first_unset();
90 // Next dump items which affect class layout.
91 for (auto &LayoutItem : Layout.layout_items()) {
92 if (NextUnusedByte >= 0) {
93 // If there are padding bytes remaining, see if this field is the first to
94 // cross a padding boundary, and print a padding field indicator if so.
95 int Off = LayoutItem->getOffsetInParent();
96 if (Off > NextUnusedByte) {
97 uint32_t Amount = Off - NextUnusedByte;
98 Printer.NewLine();
99 WithColor(Printer, PDB_ColorItem::Padding).get() << " ("
100 << Amount << " bytes)";
101 assert(UseMap.find_next(NextUnusedByte) == Off);
102 NextUnusedByte = UseMap.find_next_unset(Off);
133103 }
134104 }
135
136 if (auto Func = Child->cast()) {
137 if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
138 continue;
139
140 if (Func->getLength() == 0 && !Func->isPureVirtual() &&
141 !Func->isIntroVirtualFunction())
142 continue;
143 }
144
145 ++DumpedCount;
146 Child->dump(*this);
105 LayoutItem->getSymbol().dump(*this);
147106 }
148107
149 if (NextPaddingByte >= 0) {
150 uint32_t Amount = Size - NextPaddingByte;
108 if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) {
109 uint32_t Amount = Layout.getClassSize() - NextUnusedByte;
151110 Printer.NewLine();
152111 WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount
153112 << " bytes)";
113 DumpedAnything = true;
154114 }
115
155116 Printer.Unindent();
156 if (DumpedCount > 0)
117 if (DumpedAnything)
157118 Printer.NewLine();
158119 Printer << "}";
159120 Printer.NewLine();
160 if (Padding.count() > 0) {
161 APFloat Pct(100.0 * (double)Padding.count() /
162 (double)(Size - FirstFieldOffset));
121 if (Layout.deepPaddingSize() > 0) {
122 APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / (double)Size);
163123 SmallString<8> PctStr;
164124 Pct.toString(PctStr, 4);
165125 WithColor(Printer, PDB_ColorItem::Padding).get()
166 << "Total padding " << Padding.count() << " bytes (" << PctStr
126 << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr
167127 << "% of class size)";
168128 Printer.NewLine();
169129 }
174134 void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
175135 VariableDumper Dumper(Printer);
176136 Dumper.start(Symbol);
137 DumpedAnything = true;
177138 }
178139
179140 void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
180141 if (Printer.IsSymbolExcluded(Symbol.getName()))
181142 return;
143 if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated)
144 return;
145 if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() &&
146 !Symbol.isIntroVirtualFunction())
147 return;
182148
149 DumpedAnything = true;
183150 Printer.NewLine();
184151 FunctionDumper Dumper(Printer);
185152 Dumper.start(Symbol, FunctionDumper::PointerType::None);
186153 }
187154
188 void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
155 void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {
156 VariableDumper Dumper(Printer);
157 Dumper.start(Symbol);
158 DumpedAnything = true;
159 }
189160
190161 void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
191162 if (Printer.IsTypeExcluded(Symbol.getName()))
192163 return;
193164
165 DumpedAnything = true;
194166 Printer.NewLine();
195167 EnumDumper Dumper(Printer);
196168 Dumper.start(Symbol);
200172 if (Printer.IsTypeExcluded(Symbol.getName()))
201173 return;
202174
175 DumpedAnything = true;
203176 Printer.NewLine();
204177 TypedefDumper Dumper(Printer);
205178 Dumper.start(Symbol);
2020 #include
2121
2222 namespace llvm {
23 class BitVector;
24
2325 namespace pdb {
2426
2527 class LinePrinter;
3941 void dump(const PDBSymbolTypeVTable &Symbol) override;
4042
4143 private:
44 bool maybeDumpSymbol(std::unique_ptr Data,
45 const BitVector &Padding, int &NextUnusedByte);
46 bool maybeDumpSymbol(std::unique_ptr Data);
47 bool DumpedAnything = false;
4248 LinePrinter &Printer;
4349 };
4450 }
232232 if (!PointeeType)
233233 return;
234234
235 if (auto FuncSig = PointeeType->cast()) {
235 if (auto FuncSig = unique_dyn_cast(PointeeType)) {
236236 FunctionDumper NestedDumper(Printer);
237237 PointerType Pointer =
238238 Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
2525 using namespace llvm;
2626 using namespace llvm::pdb;
2727
28 template
29 static std::vector>
30 filterClassDefs(LinePrinter &Printer, Enumerator &E) {
31 std::vector> Filtered;
32 while (auto Class = E.getNext()) {
33 if (Class->getUnmodifiedTypeId() != 0)
34 continue;
35
36 if (Printer.IsTypeExcluded(Class->getName()))
37 continue;
38
39 Filtered.push_back(std::move(Class));
40 }
41
42 return Filtered;
43 }
44
2845 TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
2946
3047 void TypeDumper::start(const PDBSymbolExe &Exe) {
5269
5370 if (opts::pretty::Classes) {
5471 auto Classes = Exe.findAllChildren();
72 auto Filtered = filterClassDefs(Printer, *Classes);
73
5574 Printer.NewLine();
75 uint32_t Shown = Filtered.size();
76 uint32_t All = Classes->getChildCount();
77
5678 WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
57 Printer << ": (" << Classes->getChildCount() << " items)";
79 Printer << ": (Showing " << Shown << " items";
80 if (Shown < All)
81 Printer << ", " << (All - Shown) << " filtered";
82 Printer << ")";
5883 Printer.Indent();
59 while (auto Class = Classes->getNext())
84 for (auto &Class : Filtered)
6085 Class->dump(*this);
6186 Printer.Unindent();
6287 }
90115 void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
91116 assert(opts::pretty::Classes);
92117
93 if (Symbol.getUnmodifiedTypeId() != 0)
94 return;
95 if (Printer.IsTypeExcluded(Symbol.getName()))
96 return;
97
98118 if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) {
99119 Printer.NewLine();
100120 WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
5353 if (Symbol.isVolatileType())
5454 WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
5555 auto PointeeType = Symbol.getPointeeType();
56 if (auto FuncSig = PointeeType->cast()) {
56 if (auto FuncSig = unique_dyn_cast(PointeeType)) {
5757 FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
5858 if (Symbol.isReference())
5959 Pointer = FunctionDumper::PointerType::Reference;
9090 }
9191 }
9292
93 void VariableDumper::start(const PDBSymbolTypeVTable &Var) {
94 Printer.NewLine();
95 Printer << "data ";
96 auto VTableType = cast(Var.getType());
97 uint32_t PointerSize = VTableType->getLength();
98
99 WithColor(Printer, PDB_ColorItem::Offset).get()
100 << "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << PointerSize
101 << "] ";
102
103 WithColor(Printer, PDB_ColorItem::Identifier).get() << " __vfptr";
104 }
105
93106 void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) {
94107 auto ElementType = Symbol.getElementType();
95108 assert(ElementType);
156169 if (!PointeeType)
157170 return;
158171 PointeeType->dump(*this);
159 if (auto Func = PointeeType->cast()) {
172 if (auto FuncSig = unique_dyn_cast(PointeeType)) {
160173 // A hack to get the calling convention in the right spot.
161174 Printer << " (";
162 PDB_CallingConv CC = Func->getCallingConvention();
175 PDB_CallingConv CC = FuncSig->getCallingConvention();
163176 WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
164 } else if (isa(PointeeType.get())) {
177 } else if (isa(PointeeType)) {
165178 Printer << " (";
166179 }
167180 Printer << (Symbol.isReference() ? "&" : "*");
176189 assert(PointeeType);
177190 if (!PointeeType)
178191 return;
179 if (isa(PointeeType.get()) ||
180 isa(PointeeType.get())) {
192 if (isa(PointeeType) ||
193 isa(PointeeType)) {
181194 Printer << ")";
182195 }
183196 PointeeType->dumpRight(*this);
2424 VariableDumper(LinePrinter &P);
2525
2626 void start(const PDBSymbolData &Var);
27 void start(const PDBSymbolTypeVTable &Var);
2728
2829 void dump(const PDBSymbolTypeArray &Symbol) override;
2930 void dump(const PDBSymbolTypeBuiltin &Symbol) override;
9595 "Analyze various aspects of a PDB's structure");
9696
9797 cl::OptionCategory TypeCategory("Symbol Type Options");
98 cl::OptionCategory FilterCategory("Filtering Options");
98 cl::OptionCategory FilterCategory("Filtering and Sorting Options");
9999 cl::OptionCategory OtherOptions("Other Options");
100100
101101 namespace pretty {
121121 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
122122 cl::opt Typedefs("typedefs", cl::desc("Display typedef types"),
123123 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
124 cl::opt
125 ClassFormat("class-definitions", cl::desc("Class definition format"),
126 cl::init(ClassDefinitionFormat::Standard),
127 cl::values(clEnumValN(ClassDefinitionFormat::Standard, "full",
128 "Display complete class definition"),
129 clEnumValN(ClassDefinitionFormat::None, "none",
130 "Don't display class definitions")),
131 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
124 cl::opt ClassFormat(
125 "class-definitions", cl::desc("Class definition format"),
126 cl::init(ClassDefinitionFormat::Standard),
127 cl::values(
128 clEnumValN(ClassDefinitionFormat::Standard, "full",
129 "Display complete class definition"),
130 clEnumValN(ClassDefinitionFormat::Layout, "layout",
131 "Only display members that contribute to class size."),
132 clEnumValN(ClassDefinitionFormat::None, "none",
133 "Don't display class definitions")),
134 cl::cat(TypeCategory), cl::sub(PrettySubcommand));
132135
133136 cl::opt Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory),
134137 cl::sub(PrettySubcommand));
1717
1818 namespace pretty {
1919
20 enum class ClassDefinitionFormat { None, Standard };
20 enum class ClassDefinitionFormat { None, Layout, Standard };
2121
2222 extern llvm::cl::opt Compilands;
2323 extern llvm::cl::opt Symbols;
6262 class MockSession : public IPDBSession {
6363 uint64_t getLoadAddress() const override { return 0; }
6464 void setLoadAddress(uint64_t Address) override {}
65 std::unique_ptr getGlobalScope() override {
65 std::unique_ptr getGlobalScope() const override {
6666 return nullptr;
6767 }
6868 std::unique_ptr getSymbolById(uint32_t SymbolId) const override {
225225 MOCK_SYMBOL_ACCESSOR(getMachineType)
226226 MOCK_SYMBOL_ACCESSOR(getThunkOrdinal)
227227 MOCK_SYMBOL_ACCESSOR(getLength)
228 MOCK_SYMBOL_ACCESSOR(getVirtualBaseTableType)
228229 MOCK_SYMBOL_ACCESSOR(getLiveRangeLength)
229230 MOCK_SYMBOL_ACCESSOR(getVirtualAddress)
230231 MOCK_SYMBOL_ACCESSOR(getUdtKind)