xref: /freebsd/contrib/llvm-project/llvm/lib/DebugInfo/PDB/UDTLayout.cpp (revision 7877fdebeeb35fad1cbbafce22598b1bdf97c786)
1 //===- UDTLayout.cpp ------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
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"
25 #include <algorithm>
26 #include <cassert>
27 #include <cstdint>
28 #include <memory>
29 
30 using namespace llvm;
31 using namespace llvm::pdb;
32 
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);
38 }
39 
40 static uint32_t getTypeLength(const PDBSymbol &Symbol) {
41   auto SymbolType = getSymbolType(Symbol);
42   const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
43 
44   return RawType.getLength();
45 }
46 
47 LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent,
48                                const PDBSymbol *Symbol, const std::string &Name,
49                                uint32_t OffsetInParent, uint32_t Size,
50                                bool IsElided)
51     : Symbol(Symbol), Parent(Parent), Name(Name),
52       OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size),
53       IsElided(IsElided) {
54   UsedBytes.resize(SizeOf, true);
55 }
56 
57 uint32_t LayoutItemBase::deepPaddingSize() const {
58   return UsedBytes.size() - UsedBytes.count();
59 }
60 
61 uint32_t LayoutItemBase::tailPadding() const {
62   int Last = UsedBytes.find_last();
63 
64   return UsedBytes.size() - (Last + 1);
65 }
66 
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();
76   }
77 }
78 
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)) {
84 }
85 
86 const PDBSymbolData &DataMemberLayoutItem::getDataMember() {
87   return *cast<PDBSymbolData>(Symbol);
88 }
89 
90 bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; }
91 
92 const ClassLayout &DataMemberLayoutItem::getUDTLayout() const {
93   return *UdtLayout;
94 }
95 
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();
102 }
103 
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
109   // uninitialized.
110   UsedBytes.reset(0, Size);
111 
112   initializeChildren(Sym);
113   if (LayoutSize < Size)
114     UsedBytes.resize(LayoutSize);
115 }
116 
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)
123       Abs = 0;
124     else
125       Abs -= ChildPadding;
126   }
127   return Abs;
128 }
129 
130 ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT)
131     : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false),
132       UDT(UDT) {
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);
139   }
140 }
141 
142 ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)
143     : ClassLayout(*UDT) {
144   OwnedStorage = std::move(UDT);
145 }
146 
147 uint32_t ClassLayout::immediatePadding() const {
148   return SizeOf - ImmediateUsedBytes.count();
149 }
150 
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(),
155                     Elide),
156       Base(std::move(B)) {
157   if (isEmptyBase()) {
158     // Special case an empty base so that it doesn't get treated as padding.
159     UsedBytes.resize(1);
160     UsedBytes.set(0);
161   }
162   IsVirtualBase = Base->isVirtualBaseClass();
163 }
164 
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;
174 
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));
180       else
181         Bases.push_back(std::move(Base));
182     }
183     else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) {
184       if (Data->getDataKind() == PDB_DataKind::Member)
185         Members.push_back(std::move(Data));
186       else
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));
192     else {
193       Other.push_back(std::move(Child));
194     }
195   }
196 
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());
200 
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,
209                                                  std::move(Base));
210 
211     AllBases.push_back(BL.get());
212     addChildToLayout(std::move(BL));
213   }
214   NonVirtualBases = AllBases;
215 
216   assert(VTables.size() <= 1);
217   if (!VTables.empty()) {
218     auto VTLayout =
219         std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0]));
220 
221     VTable = VTLayout.get();
222 
223     addChildToLayout(std::move(VTLayout));
224   }
225 
226   for (auto &Data : Members) {
227     auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data));
228 
229     addChildToLayout(std::move(DM));
230   }
231 
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());
241         VBPtr = VBPL.get();
242         addChildToLayout(std::move(VBPL));
243       }
244     }
245 
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
249     // class.
250     uint32_t Offset = UsedBytes.find_last() + 1;
251     bool Elide = (Parent != nullptr);
252     auto BL =
253         std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB));
254     AllBases.push_back(BL.get());
255 
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));
260   }
261   VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size());
262 
263   if (Parent != nullptr)
264     LayoutSize = UsedBytes.find_last() + 1;
265 }
266 
267 bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const {
268   if (VBPtr && VBPtr->getOffsetInParent() == Off)
269     return true;
270   for (BaseClassLayout *BL : AllBases) {
271     if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent()))
272       return true;
273   }
274   return false;
275 }
276 
277 void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) {
278   uint32_t Begin = Child->getOffsetInParent();
279 
280   if (!Child->isElided()) {
281     BitVector ChildBytes = Child->usedBytes();
282 
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;
290 
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());
295                                   });
296 
297       LayoutItems.insert(Loc, Child.get());
298     }
299   }
300 
301   ChildStorage.push_back(std::move(Child));
302 }
303