1 //===- UDTLayout.cpp ------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/PDB/UDTLayout.h"
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/BitVector.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
14 #include "llvm/DebugInfo/PDB/IPDBSession.h"
15 #include "llvm/DebugInfo/PDB/PDBSymbol.h"
16 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
17 #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
18 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
19 #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
20 #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
21 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
22 #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
23 #include "llvm/DebugInfo/PDB/PDBTypes.h"
24 #include "llvm/Support/Casting.h"
31 using namespace llvm::pdb
;
33 static std::unique_ptr
<PDBSymbol
> getSymbolType(const PDBSymbol
&Symbol
) {
34 const IPDBSession
&Session
= Symbol
.getSession();
35 const IPDBRawSymbol
&RawSymbol
= Symbol
.getRawSymbol();
36 uint32_t TypeId
= RawSymbol
.getTypeId();
37 return Session
.getSymbolById(TypeId
);
40 static uint32_t getTypeLength(const PDBSymbol
&Symbol
) {
41 auto SymbolType
= getSymbolType(Symbol
);
42 const IPDBRawSymbol
&RawType
= SymbolType
->getRawSymbol();
44 return RawType
.getLength();
47 LayoutItemBase::LayoutItemBase(const UDTLayoutBase
*Parent
,
48 const PDBSymbol
*Symbol
, const std::string
&Name
,
49 uint32_t OffsetInParent
, uint32_t Size
,
51 : Symbol(Symbol
), Parent(Parent
), Name(Name
),
52 OffsetInParent(OffsetInParent
), SizeOf(Size
), LayoutSize(Size
),
54 UsedBytes
.resize(SizeOf
, true);
57 uint32_t LayoutItemBase::deepPaddingSize() const {
58 return UsedBytes
.size() - UsedBytes
.count();
61 uint32_t LayoutItemBase::tailPadding() const {
62 int Last
= UsedBytes
.find_last();
64 return UsedBytes
.size() - (Last
+ 1);
67 DataMemberLayoutItem::DataMemberLayoutItem(
68 const UDTLayoutBase
&Parent
, std::unique_ptr
<PDBSymbolData
> Member
)
69 : LayoutItemBase(&Parent
, Member
.get(), Member
->getName(),
70 Member
->getOffset(), getTypeLength(*Member
), false),
71 DataMember(std::move(Member
)) {
72 auto Type
= DataMember
->getType();
73 if (auto UDT
= unique_dyn_cast
<PDBSymbolTypeUDT
>(Type
)) {
74 UdtLayout
= std::make_unique
<ClassLayout
>(std::move(UDT
));
75 UsedBytes
= UdtLayout
->usedBytes();
79 VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase
&Parent
,
80 std::unique_ptr
<PDBSymbolTypeBuiltin
> Sym
,
81 uint32_t Offset
, uint32_t Size
)
82 : LayoutItemBase(&Parent
, Sym
.get(), "<vbptr>", Offset
, Size
, false),
83 Type(std::move(Sym
)) {
86 const PDBSymbolData
&DataMemberLayoutItem::getDataMember() {
87 return *cast
<PDBSymbolData
>(Symbol
);
90 bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout
!= nullptr; }
92 const ClassLayout
&DataMemberLayoutItem::getUDTLayout() const {
96 VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase
&Parent
,
97 std::unique_ptr
<PDBSymbolTypeVTable
> VT
)
98 : LayoutItemBase(&Parent
, VT
.get(), "<vtbl>", 0, getTypeLength(*VT
), false),
99 VTable(std::move(VT
)) {
100 auto VTableType
= cast
<PDBSymbolTypePointer
>(VTable
->getType());
101 ElementSize
= VTableType
->getLength();
104 UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase
*Parent
, const PDBSymbol
&Sym
,
105 const std::string
&Name
, uint32_t OffsetInParent
,
106 uint32_t Size
, bool IsElided
)
107 : LayoutItemBase(Parent
, &Sym
, Name
, OffsetInParent
, Size
, IsElided
) {
108 // UDT storage comes from a union of all the children's storage, so start out
110 UsedBytes
.reset(0, Size
);
112 initializeChildren(Sym
);
113 if (LayoutSize
< Size
)
114 UsedBytes
.resize(LayoutSize
);
117 uint32_t UDTLayoutBase::tailPadding() const {
118 uint32_t Abs
= LayoutItemBase::tailPadding();
119 if (!LayoutItems
.empty()) {
120 const LayoutItemBase
*Back
= LayoutItems
.back();
121 uint32_t ChildPadding
= Back
->LayoutItemBase::tailPadding();
122 if (Abs
< ChildPadding
)
130 ClassLayout::ClassLayout(const PDBSymbolTypeUDT
&UDT
)
131 : UDTLayoutBase(nullptr, UDT
, UDT
.getName(), 0, UDT
.getLength(), false),
133 ImmediateUsedBytes
.resize(SizeOf
, false);
134 for (auto &LI
: LayoutItems
) {
135 uint32_t Begin
= LI
->getOffsetInParent();
136 uint32_t End
= Begin
+ LI
->getLayoutSize();
137 End
= std::min(SizeOf
, End
);
138 ImmediateUsedBytes
.set(Begin
, End
);
142 ClassLayout::ClassLayout(std::unique_ptr
<PDBSymbolTypeUDT
> UDT
)
143 : ClassLayout(*UDT
) {
144 OwnedStorage
= std::move(UDT
);
147 uint32_t ClassLayout::immediatePadding() const {
148 return SizeOf
- ImmediateUsedBytes
.count();
151 BaseClassLayout::BaseClassLayout(const UDTLayoutBase
&Parent
,
152 uint32_t OffsetInParent
, bool Elide
,
153 std::unique_ptr
<PDBSymbolTypeBaseClass
> B
)
154 : UDTLayoutBase(&Parent
, *B
, B
->getName(), OffsetInParent
, B
->getLength(),
158 // Special case an empty base so that it doesn't get treated as padding.
162 IsVirtualBase
= Base
->isVirtualBaseClass();
165 void UDTLayoutBase::initializeChildren(const PDBSymbol
&Sym
) {
166 // Handled bases first, followed by VTables, followed by data members,
167 // followed by functions, followed by other. This ordering is necessary
168 // so that bases and vtables get initialized before any functions which
169 // may override them.
170 UniquePtrVector
<PDBSymbolTypeBaseClass
> Bases
;
171 UniquePtrVector
<PDBSymbolTypeVTable
> VTables
;
172 UniquePtrVector
<PDBSymbolData
> Members
;
173 UniquePtrVector
<PDBSymbolTypeBaseClass
> VirtualBaseSyms
;
175 auto Children
= Sym
.findAllChildren();
176 while (auto Child
= Children
->getNext()) {
177 if (auto Base
= unique_dyn_cast
<PDBSymbolTypeBaseClass
>(Child
)) {
178 if (Base
->isVirtualBaseClass())
179 VirtualBaseSyms
.push_back(std::move(Base
));
181 Bases
.push_back(std::move(Base
));
183 else if (auto Data
= unique_dyn_cast
<PDBSymbolData
>(Child
)) {
184 if (Data
->getDataKind() == PDB_DataKind::Member
)
185 Members
.push_back(std::move(Data
));
187 Other
.push_back(std::move(Data
));
188 } else if (auto VT
= unique_dyn_cast
<PDBSymbolTypeVTable
>(Child
))
189 VTables
.push_back(std::move(VT
));
190 else if (auto Func
= unique_dyn_cast
<PDBSymbolFunc
>(Child
))
191 Funcs
.push_back(std::move(Func
));
193 Other
.push_back(std::move(Child
));
197 // We don't want to have any re-allocations in the list of bases, so make
198 // sure to reserve enough space so that our ArrayRefs don't get invalidated.
199 AllBases
.reserve(Bases
.size() + VirtualBaseSyms
.size());
201 // Only add non-virtual bases to the class first. Only at the end of the
202 // class, after all non-virtual bases and data members have been added do we
203 // add virtual bases. This way the offsets are correctly aligned when we go
204 // to lay out virtual bases.
205 for (auto &Base
: Bases
) {
206 uint32_t Offset
= Base
->getOffset();
207 // Non-virtual bases never get elided.
208 auto BL
= std::make_unique
<BaseClassLayout
>(*this, Offset
, false,
211 AllBases
.push_back(BL
.get());
212 addChildToLayout(std::move(BL
));
214 NonVirtualBases
= AllBases
;
216 assert(VTables
.size() <= 1);
217 if (!VTables
.empty()) {
219 std::make_unique
<VTableLayoutItem
>(*this, std::move(VTables
[0]));
221 VTable
= VTLayout
.get();
223 addChildToLayout(std::move(VTLayout
));
226 for (auto &Data
: Members
) {
227 auto DM
= std::make_unique
<DataMemberLayoutItem
>(*this, std::move(Data
));
229 addChildToLayout(std::move(DM
));
232 // Make sure add virtual bases before adding functions, since functions may be
233 // overrides of virtual functions declared in a virtual base, so the VTables
234 // and virtual intros need to be correctly initialized.
235 for (auto &VB
: VirtualBaseSyms
) {
236 int VBPO
= VB
->getVirtualBasePointerOffset();
237 if (!hasVBPtrAtOffset(VBPO
)) {
238 if (auto VBP
= VB
->getRawSymbol().getVirtualBaseTableType()) {
239 auto VBPL
= std::make_unique
<VBPtrLayoutItem
>(*this, std::move(VBP
),
240 VBPO
, VBP
->getLength());
242 addChildToLayout(std::move(VBPL
));
246 // Virtual bases always go at the end. So just look for the last place we
247 // ended when writing something, and put our virtual base there.
248 // Note that virtual bases get elided unless this is a top-most derived
250 uint32_t Offset
= UsedBytes
.find_last() + 1;
251 bool Elide
= (Parent
!= nullptr);
253 std::make_unique
<BaseClassLayout
>(*this, Offset
, Elide
, std::move(VB
));
254 AllBases
.push_back(BL
.get());
256 // Only lay this virtual base out directly inside of *this* class if this
257 // is a top-most derived class. Keep track of it regardless, but only
258 // physically lay it out if it's a topmost derived class.
259 addChildToLayout(std::move(BL
));
261 VirtualBases
= makeArrayRef(AllBases
).drop_front(NonVirtualBases
.size());
263 if (Parent
!= nullptr)
264 LayoutSize
= UsedBytes
.find_last() + 1;
267 bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off
) const {
268 if (VBPtr
&& VBPtr
->getOffsetInParent() == Off
)
270 for (BaseClassLayout
*BL
: AllBases
) {
271 if (BL
->hasVBPtrAtOffset(Off
- BL
->getOffsetInParent()))
277 void UDTLayoutBase::addChildToLayout(std::unique_ptr
<LayoutItemBase
> Child
) {
278 uint32_t Begin
= Child
->getOffsetInParent();
280 if (!Child
->isElided()) {
281 BitVector ChildBytes
= Child
->usedBytes();
283 // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte
284 // class. When we call ChildBytes.resize(32), the Child's storage will
285 // still begin at offset 0, so we need to shift it left by offset bytes
286 // to get it into the right position.
287 ChildBytes
.resize(UsedBytes
.size());
288 ChildBytes
<<= Child
->getOffsetInParent();
289 UsedBytes
|= ChildBytes
;
291 if (ChildBytes
.count() > 0) {
292 auto Loc
= std::upper_bound(LayoutItems
.begin(), LayoutItems
.end(), Begin
,
293 [](uint32_t Off
, const LayoutItemBase
*Item
) {
294 return (Off
< Item
->getOffsetInParent());
297 LayoutItems
.insert(Loc
, Child
.get());
301 ChildStorage
.push_back(std::move(Child
));