blob: 5f4390bbaf12ba042f50ae133a70e6b7f4f8e2b4 [file] [log] [blame]
Eugene Zelenko4fcfc192017-06-30 23:06:03 +00001//===- UDTLayout.cpp ------------------------------------------------------===//
Zachary Turnerc883a8c2017-04-12 23:18:21 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/DebugInfo/PDB/UDTLayout.h"
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000011#include "llvm/ADT/ArrayRef.h"
12#include "llvm/ADT/BitVector.h"
Zachary Turner4dc4f012017-04-13 21:11:00 +000013#include "llvm/ADT/STLExtras.h"
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000014#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
Zachary Turnerc883a8c2017-04-12 23:18:21 +000015#include "llvm/DebugInfo/PDB/IPDBSession.h"
16#include "llvm/DebugInfo/PDB/PDBSymbol.h"
17#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
Zachary Turnerc883a8c2017-04-12 23:18:21 +000018#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
19#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
Zachary Turner16901642017-04-24 17:47:24 +000020#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
Zachary Turnerc883a8c2017-04-12 23:18:21 +000021#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
22#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
23#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
Eugene Zelenko4fcfc192017-06-30 23:06:03 +000024#include "llvm/DebugInfo/PDB/PDBTypes.h"
25#include "llvm/Support/Casting.h"
26#include <algorithm>
27#include <cassert>
28#include <cstdint>
29#include <memory>
Zachary Turnerc883a8c2017-04-12 23:18:21 +000030
31using namespace llvm;
32using namespace llvm::pdb;
33
34static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) {
35 const IPDBSession &Session = Symbol.getSession();
36 const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol();
37 uint32_t TypeId = RawSymbol.getTypeId();
38 return Session.getSymbolById(TypeId);
39}
40
41static uint32_t getTypeLength(const PDBSymbol &Symbol) {
42 auto SymbolType = getSymbolType(Symbol);
43 const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
44
45 return RawType.getLength();
46}
47
Zachary Turner16901642017-04-24 17:47:24 +000048LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent,
49 const PDBSymbol *Symbol, const std::string &Name,
50 uint32_t OffsetInParent, uint32_t Size,
51 bool IsElided)
52 : Symbol(Symbol), Parent(Parent), Name(Name),
53 OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size),
54 IsElided(IsElided) {
Zachary Turnerc883a8c2017-04-12 23:18:21 +000055 UsedBytes.resize(SizeOf, true);
56}
57
Zachary Turner16901642017-04-24 17:47:24 +000058uint32_t LayoutItemBase::deepPaddingSize() const {
59 return UsedBytes.size() - UsedBytes.count();
Zachary Turnerc883a8c2017-04-12 23:18:21 +000060}
61
Zachary Turner16901642017-04-24 17:47:24 +000062uint32_t LayoutItemBase::tailPadding() const {
63 int Last = UsedBytes.find_last();
64
65 return UsedBytes.size() - (Last + 1);
66}
67
Zachary Turnerc883a8c2017-04-12 23:18:21 +000068DataMemberLayoutItem::DataMemberLayoutItem(
Zachary Turner16901642017-04-24 17:47:24 +000069 const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member)
70 : LayoutItemBase(&Parent, Member.get(), Member->getName(),
71 Member->getOffset(), getTypeLength(*Member), false),
72 DataMember(std::move(Member)) {
73 auto Type = DataMember->getType();
Zachary Turnerc883a8c2017-04-12 23:18:21 +000074 if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) {
Zachary Turnerc883a8c2017-04-12 23:18:21 +000075 UdtLayout = llvm::make_unique<ClassLayout>(std::move(UDT));
Zachary Turner16901642017-04-24 17:47:24 +000076 UsedBytes = UdtLayout->usedBytes();
Zachary Turnerc883a8c2017-04-12 23:18:21 +000077 }
78}
79
Zachary Turner16901642017-04-24 17:47:24 +000080VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent,
81 std::unique_ptr<PDBSymbolTypeBuiltin> Sym,
82 uint32_t Offset, uint32_t Size)
83 : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false),
84 Type(std::move(Sym)) {
85}
86
Zachary Turnerc883a8c2017-04-12 23:18:21 +000087const PDBSymbolData &DataMemberLayoutItem::getDataMember() {
Zachary Turner16901642017-04-24 17:47:24 +000088 return *dyn_cast<PDBSymbolData>(Symbol);
Zachary Turnerc883a8c2017-04-12 23:18:21 +000089}
90
Zachary Turner4dc4f012017-04-13 21:11:00 +000091bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; }
92
93const ClassLayout &DataMemberLayoutItem::getUDTLayout() const {
94 return *UdtLayout;
95}
96
Zachary Turnerc883a8c2017-04-12 23:18:21 +000097VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,
Zachary Turner16901642017-04-24 17:47:24 +000098 std::unique_ptr<PDBSymbolTypeVTable> VT)
99 : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false),
100 VTable(std::move(VT)) {
101 auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType());
Zachary Turner4dc4f012017-04-13 21:11:00 +0000102 ElementSize = VTableType->getLength();
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000103}
104
Zachary Turner16901642017-04-24 17:47:24 +0000105UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym,
106 const std::string &Name, uint32_t OffsetInParent,
107 uint32_t Size, bool IsElided)
108 : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) {
109 // UDT storage comes from a union of all the children's storage, so start out
110 // uninitialized.
111 UsedBytes.reset(0, Size);
112
113 initializeChildren(Sym);
114 if (LayoutSize < Size)
115 UsedBytes.resize(LayoutSize);
116}
117
118uint32_t UDTLayoutBase::tailPadding() const {
119 uint32_t Abs = LayoutItemBase::tailPadding();
120 if (!LayoutItems.empty()) {
121 const LayoutItemBase *Back = LayoutItems.back();
122 uint32_t ChildPadding = Back->LayoutItemBase::tailPadding();
123 if (Abs < ChildPadding)
124 Abs = 0;
125 else
126 Abs -= ChildPadding;
127 }
128 return Abs;
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000129}
130
Zachary Turner9e7dda32017-04-12 23:18:51 +0000131ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT)
Zachary Turner16901642017-04-24 17:47:24 +0000132 : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false),
Zachary Turnerda307b62017-04-25 20:22:29 +0000133 UDT(UDT) {
134 ImmediateUsedBytes.resize(SizeOf, false);
135 for (auto &LI : LayoutItems) {
136 uint32_t Begin = LI->getOffsetInParent();
137 uint32_t End = Begin + LI->getLayoutSize();
138 End = std::min(SizeOf, End);
139 ImmediateUsedBytes.set(Begin, End);
140 }
141}
Zachary Turner9e7dda32017-04-12 23:18:51 +0000142
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000143ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)
Zachary Turner9e7dda32017-04-12 23:18:51 +0000144 : ClassLayout(*UDT) {
145 OwnedStorage = std::move(UDT);
146}
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000147
Zachary Turnerda307b62017-04-25 20:22:29 +0000148uint32_t ClassLayout::immediatePadding() const {
149 return SizeOf - ImmediateUsedBytes.count();
150}
151
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000152BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent,
Zachary Turner16901642017-04-24 17:47:24 +0000153 uint32_t OffsetInParent, bool Elide,
154 std::unique_ptr<PDBSymbolTypeBaseClass> B)
155 : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(),
156 Elide),
157 Base(std::move(B)) {
158 if (isEmptyBase()) {
159 // Special case an empty base so that it doesn't get treated as padding.
160 UsedBytes.resize(1);
161 UsedBytes.set(0);
162 }
163 IsVirtualBase = Base->isVirtualBaseClass();
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000164}
165
166void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) {
Zachary Turner4dc4f012017-04-13 21:11:00 +0000167 // Handled bases first, followed by VTables, followed by data members,
168 // followed by functions, followed by other. This ordering is necessary
169 // so that bases and vtables get initialized before any functions which
170 // may override them.
Zachary Turner4dc4f012017-04-13 21:11:00 +0000171 UniquePtrVector<PDBSymbolTypeBaseClass> Bases;
172 UniquePtrVector<PDBSymbolTypeVTable> VTables;
173 UniquePtrVector<PDBSymbolData> Members;
Zachary Turner16901642017-04-24 17:47:24 +0000174 UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms;
175
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000176 auto Children = Sym.findAllChildren();
177 while (auto Child = Children->getNext()) {
Zachary Turner4dc4f012017-04-13 21:11:00 +0000178 if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
179 if (Base->isVirtualBaseClass())
Zachary Turner16901642017-04-24 17:47:24 +0000180 VirtualBaseSyms.push_back(std::move(Base));
Zachary Turner4dc4f012017-04-13 21:11:00 +0000181 else
182 Bases.push_back(std::move(Base));
183 }
Zachary Turner4dc4f012017-04-13 21:11:00 +0000184 else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) {
185 if (Data->getDataKind() == PDB_DataKind::Member)
186 Members.push_back(std::move(Data));
187 else
Zachary Turnerd334ceb2017-06-12 20:46:35 +0000188 Other.push_back(std::move(Data));
Zachary Turner4dc4f012017-04-13 21:11:00 +0000189 } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child))
190 VTables.push_back(std::move(VT));
191 else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child))
192 Funcs.push_back(std::move(Func));
Zachary Turnerd334ceb2017-06-12 20:46:35 +0000193 else {
Zachary Turner4dc4f012017-04-13 21:11:00 +0000194 Other.push_back(std::move(Child));
Zachary Turnerd334ceb2017-06-12 20:46:35 +0000195 }
Zachary Turner4dc4f012017-04-13 21:11:00 +0000196 }
197
Zachary Turner16901642017-04-24 17:47:24 +0000198 // We don't want to have any re-allocations in the list of bases, so make
199 // sure to reserve enough space so that our ArrayRefs don't get invalidated.
200 AllBases.reserve(Bases.size() + VirtualBaseSyms.size());
Zachary Turner4dc4f012017-04-13 21:11:00 +0000201
Zachary Turner16901642017-04-24 17:47:24 +0000202 // Only add non-virtual bases to the class first. Only at the end of the
203 // class, after all non-virtual bases and data members have been added do we
204 // add virtual bases. This way the offsets are correctly aligned when we go
205 // to lay out virtual bases.
206 for (auto &Base : Bases) {
207 uint32_t Offset = Base->getOffset();
208 // Non-virtual bases never get elided.
209 auto BL = llvm::make_unique<BaseClassLayout>(*this, Offset, false,
210 std::move(Base));
211
212 AllBases.push_back(BL.get());
Zachary Turner4dc4f012017-04-13 21:11:00 +0000213 addChildToLayout(std::move(BL));
214 }
Zachary Turner16901642017-04-24 17:47:24 +0000215 NonVirtualBases = AllBases;
Zachary Turner4dc4f012017-04-13 21:11:00 +0000216
Zachary Turner16901642017-04-24 17:47:24 +0000217 assert(VTables.size() <= 1);
218 if (!VTables.empty()) {
219 auto VTLayout =
220 llvm::make_unique<VTableLayoutItem>(*this, std::move(VTables[0]));
Zachary Turner4dc4f012017-04-13 21:11:00 +0000221
222 VTable = VTLayout.get();
223
224 addChildToLayout(std::move(VTLayout));
Zachary Turner4dc4f012017-04-13 21:11:00 +0000225 }
226
227 for (auto &Data : Members) {
228 auto DM = llvm::make_unique<DataMemberLayoutItem>(*this, std::move(Data));
229
230 addChildToLayout(std::move(DM));
231 }
232
Zachary Turner16901642017-04-24 17:47:24 +0000233 // Make sure add virtual bases before adding functions, since functions may be
234 // overrides of virtual functions declared in a virtual base, so the VTables
235 // and virtual intros need to be correctly initialized.
236 for (auto &VB : VirtualBaseSyms) {
237 int VBPO = VB->getVirtualBasePointerOffset();
238 if (!hasVBPtrAtOffset(VBPO)) {
239 if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) {
240 auto VBPL = llvm::make_unique<VBPtrLayoutItem>(*this, std::move(VBP),
241 VBPO, VBP->getLength());
242 VBPtr = VBPL.get();
243 addChildToLayout(std::move(VBPL));
Zachary Turner4dc4f012017-04-13 21:11:00 +0000244 }
245 }
Zachary Turner4dc4f012017-04-13 21:11:00 +0000246
Zachary Turner16901642017-04-24 17:47:24 +0000247 // Virtual bases always go at the end. So just look for the last place we
248 // ended when writing something, and put our virtual base there.
249 // Note that virtual bases get elided unless this is a top-most derived
250 // class.
251 uint32_t Offset = UsedBytes.find_last() + 1;
252 bool Elide = (Parent != nullptr);
253 auto BL =
254 llvm::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB));
255 AllBases.push_back(BL.get());
256
257 // Only lay this virtual base out directly inside of *this* class if this
258 // is a top-most derived class. Keep track of it regardless, but only
259 // physically lay it out if it's a topmost derived class.
260 addChildToLayout(std::move(BL));
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000261 }
Zachary Turner16901642017-04-24 17:47:24 +0000262 VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size());
263
264 if (Parent != nullptr)
265 LayoutSize = UsedBytes.find_last() + 1;
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000266}
267
Zachary Turner16901642017-04-24 17:47:24 +0000268bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const {
269 if (VBPtr && VBPtr->getOffsetInParent() == Off)
270 return true;
271 for (BaseClassLayout *BL : AllBases) {
272 if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent()))
273 return true;
274 }
275 return false;
276}
277
278void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) {
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000279 uint32_t Begin = Child->getOffsetInParent();
Zachary Turner4dc4f012017-04-13 21:11:00 +0000280
Zachary Turner16901642017-04-24 17:47:24 +0000281 if (!Child->isElided()) {
282 BitVector ChildBytes = Child->usedBytes();
283
284 // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte
285 // class. When we call ChildBytes.resize(32), the Child's storage will
286 // still begin at offset 0, so we need to shift it left by offset bytes
287 // to get it into the right position.
288 ChildBytes.resize(UsedBytes.size());
289 ChildBytes <<= Child->getOffsetInParent();
290 UsedBytes |= ChildBytes;
291
292 if (ChildBytes.count() > 0) {
293 auto Loc = std::upper_bound(LayoutItems.begin(), LayoutItems.end(), Begin,
294 [](uint32_t Off, const LayoutItemBase *Item) {
295 return (Off < Item->getOffsetInParent());
296 });
297
298 LayoutItems.insert(Loc, Child.get());
299 }
Zachary Turnerc883a8c2017-04-12 23:18:21 +0000300 }
301
Zachary Turner16901642017-04-24 17:47:24 +0000302 ChildStorage.push_back(std::move(Child));
Eugene Zelenko4fcfc192017-06-30 23:06:03 +0000303}