LLVM 22.0.0git
UDTLayout.cpp
Go to the documentation of this file.
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
10#include "llvm/ADT/ArrayRef.h"
11#include "llvm/ADT/BitVector.h"
12#include "llvm/ADT/STLExtras.h"
27#include <algorithm>
28#include <cassert>
29#include <cstdint>
30#include <memory>
31
32using namespace llvm;
33using namespace llvm::pdb;
34
35static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) {
36 const IPDBSession &Session = Symbol.getSession();
37 const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol();
38 uint32_t TypeId = RawSymbol.getTypeId();
39 return Session.getSymbolById(TypeId);
40}
41
42static uint32_t getTypeLength(const PDBSymbol &Symbol) {
43 auto SymbolType = getSymbolType(Symbol);
44 const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
45
46 return RawType.getLength();
47}
48
50 const PDBSymbol *Symbol, const std::string &Name,
51 uint32_t OffsetInParent, uint32_t Size,
52 bool IsElided)
53 : Symbol(Symbol), Parent(Parent), Name(Name),
54 OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size),
55 IsElided(IsElided) {
56 UsedBytes.resize(SizeOf, true);
57}
58
60 return UsedBytes.size() - UsedBytes.count();
61}
62
64 int Last = UsedBytes.find_last();
65
66 return UsedBytes.size() - (Last + 1);
67}
68
70 const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member)
71 : LayoutItemBase(&Parent, Member.get(), Member->getName(),
73 DataMember(std::move(Member)) {
74 auto Type = DataMember->getType();
75 if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) {
76 UdtLayout = std::make_unique<ClassLayout>(std::move(UDT));
77 UsedBytes = UdtLayout->usedBytes();
78 }
79}
80
82 std::unique_ptr<PDBSymbolTypeBuiltin> Sym,
84 : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false),
85 Type(std::move(Sym)) {
86}
87
89 return *cast<PDBSymbolData>(Symbol);
90}
91
92bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; }
93
95 return *UdtLayout;
96}
97
99 std::unique_ptr<PDBSymbolTypeVTable> VT)
100 : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false),
101 VTable(std::move(VT)) {
102 auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType());
103 ElementSize = VTableType->getLength();
104}
105
107 const std::string &Name, uint32_t OffsetInParent,
108 uint32_t Size, bool IsElided)
109 : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) {
110 // UDT storage comes from a union of all the children's storage, so start out
111 // uninitialized.
112 UsedBytes.reset(0, Size);
113
115 if (LayoutSize < Size)
117}
118
121 if (!LayoutItems.empty()) {
122 const LayoutItemBase *Back = LayoutItems.back();
123 uint32_t ChildPadding = Back->LayoutItemBase::tailPadding();
124 if (Abs < ChildPadding)
125 Abs = 0;
126 else
127 Abs -= ChildPadding;
128 }
129 return Abs;
130}
131
133 : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false),
134 UDT(UDT) {
135 ImmediateUsedBytes.resize(SizeOf, false);
136 for (auto &LI : LayoutItems) {
137 uint32_t Begin = LI->getOffsetInParent();
138 uint32_t End = Begin + LI->getLayoutSize();
139 End = std::min(SizeOf, End);
140 ImmediateUsedBytes.set(Begin, End);
141 }
142}
143
144ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)
145 : ClassLayout(*UDT) {
146 OwnedStorage = std::move(UDT);
147}
148
150 return SizeOf - ImmediateUsedBytes.count();
151}
152
154 uint32_t OffsetInParent, bool Elide,
155 std::unique_ptr<PDBSymbolTypeBaseClass> B)
156 : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(),
157 Elide),
158 Base(std::move(B)) {
159 if (isEmptyBase()) {
160 // Special case an empty base so that it doesn't get treated as padding.
161 UsedBytes.resize(1);
162 UsedBytes.set(0);
163 }
164 IsVirtualBase = Base->isVirtualBaseClass();
165}
166
168 // Handled bases first, followed by VTables, followed by data members,
169 // followed by functions, followed by other. This ordering is necessary
170 // so that bases and vtables get initialized before any functions which
171 // may override them.
172 UniquePtrVector<PDBSymbolTypeBaseClass> Bases;
173 UniquePtrVector<PDBSymbolTypeVTable> VTables;
174 UniquePtrVector<PDBSymbolData> Members;
175 UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms;
176
177 auto Children = Sym.findAllChildren();
178 while (auto Child = Children->getNext()) {
179 if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
180 if (Base->isVirtualBaseClass())
181 VirtualBaseSyms.push_back(std::move(Base));
182 else
183 Bases.push_back(std::move(Base));
184 }
185 else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) {
186 if (Data->getDataKind() == PDB_DataKind::Member)
187 Members.push_back(std::move(Data));
188 else
189 Other.push_back(std::move(Data));
190 } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child))
191 VTables.push_back(std::move(VT));
192 else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child))
193 Funcs.push_back(std::move(Func));
194 else {
195 Other.push_back(std::move(Child));
196 }
197 }
198
199 // We don't want to have any re-allocations in the list of bases, so make
200 // sure to reserve enough space so that our ArrayRefs don't get invalidated.
201 AllBases.reserve(Bases.size() + VirtualBaseSyms.size());
202
203 // Only add non-virtual bases to the class first. Only at the end of the
204 // class, after all non-virtual bases and data members have been added do we
205 // add virtual bases. This way the offsets are correctly aligned when we go
206 // to lay out virtual bases.
207 for (auto &Base : Bases) {
208 uint32_t Offset = Base->getOffset();
209 // Non-virtual bases never get elided.
210 auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false,
211 std::move(Base));
212
213 AllBases.push_back(BL.get());
214 addChildToLayout(std::move(BL));
215 }
217
218 assert(VTables.size() <= 1);
219 if (!VTables.empty()) {
220 auto VTLayout =
221 std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0]));
222
223 VTable = VTLayout.get();
224
225 addChildToLayout(std::move(VTLayout));
226 }
227
228 for (auto &Data : Members) {
229 auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data));
230
231 addChildToLayout(std::move(DM));
232 }
233
234 // Make sure add virtual bases before adding functions, since functions may be
235 // overrides of virtual functions declared in a virtual base, so the VTables
236 // and virtual intros need to be correctly initialized.
237 for (auto &VB : VirtualBaseSyms) {
238 int VBPO = VB->getVirtualBasePointerOffset();
239 if (!hasVBPtrAtOffset(VBPO)) {
240 if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) {
241 auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP),
242 VBPO, VBP->getLength());
243 VBPtr = VBPL.get();
244 addChildToLayout(std::move(VBPL));
245 }
246 }
247
248 // Virtual bases always go at the end. So just look for the last place we
249 // ended when writing something, and put our virtual base there.
250 // Note that virtual bases get elided unless this is a top-most derived
251 // class.
253 bool Elide = (Parent != nullptr);
254 auto BL =
255 std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB));
256 AllBases.push_back(BL.get());
257
258 // Only lay this virtual base out directly inside of *this* class if this
259 // is a top-most derived class. Keep track of it regardless, but only
260 // physically lay it out if it's a topmost derived class.
261 addChildToLayout(std::move(BL));
262 }
264
265 if (Parent != nullptr)
267}
268
270 if (VBPtr && VBPtr->getOffsetInParent() == Off)
271 return true;
272 for (BaseClassLayout *BL : AllBases) {
273 if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent()))
274 return true;
275 }
276 return false;
277}
278
279void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) {
280 uint32_t Begin = Child->getOffsetInParent();
281
282 if (!Child->isElided()) {
283 BitVector ChildBytes = Child->usedBytes();
284
285 // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte
286 // class. When we call ChildBytes.resize(32), the Child's storage will
287 // still begin at offset 0, so we need to shift it left by offset bytes
288 // to get it into the right position.
289 ChildBytes.resize(UsedBytes.size());
290 ChildBytes <<= Child->getOffsetInParent();
291 UsedBytes |= ChildBytes;
292
293 if (ChildBytes.count() > 0) {
294 auto Loc = llvm::upper_bound(
295 LayoutItems, Begin, [](uint32_t Off, const LayoutItemBase *Item) {
296 return (Off < Item->getOffsetInParent());
297 });
298
299 LayoutItems.insert(Loc, Child.get());
300 }
301 }
302
303 ChildStorage.push_back(std::move(Child));
304}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements the BitVector class.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static RegisterPass< DebugifyModulePass > DM("debugify", "Attach debug info to everything")
std::string Name
uint64_t Size
bool End
Definition: ELF_riscv.cpp:480
Symbol * Sym
Definition: ELF_riscv.cpp:479
static StringRef getName(Value *V)
This file contains some templates that are useful if you are working with the STL at all.
static uint32_t getTypeLength(const PDBSymbol &Symbol)
Definition: UDTLayout.cpp:42
static std::unique_ptr< PDBSymbol > getSymbolType(const PDBSymbol &Symbol)
Definition: UDTLayout.cpp:35
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition: ArrayRef.h:200
BitVector & reset()
Definition: BitVector.h:392
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Definition: BitVector.h:341
int find_last() const
find_last - Returns the index of the last set bit, -1 if none of the bits are set.
Definition: BitVector.h:304
size_type count() const
count - Returns the number of bits which are set.
Definition: BitVector.h:162
BitVector & set()
Definition: BitVector.h:351
size_type size() const
size - Returns the number of bits in this bitvector.
Definition: BitVector.h:159
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM_ABI BaseClassLayout(const UDTLayoutBase &Parent, uint32_t OffsetInParent, bool Elide, std::unique_ptr< PDBSymbolTypeBaseClass > Base)
Definition: UDTLayout.cpp:153
uint32_t immediatePadding() const override
Definition: UDTLayout.cpp:149
ClassLayout(const PDBSymbolTypeUDT &UDT)
Definition: UDTLayout.cpp:132
LLVM_ABI const PDBSymbolData & getDataMember()
Definition: UDTLayout.cpp:88
LLVM_ABI DataMemberLayoutItem(const UDTLayoutBase &Parent, std::unique_ptr< PDBSymbolData > DataMember)
Definition: UDTLayout.cpp:69
LLVM_ABI bool hasUDTLayout() const
Definition: UDTLayout.cpp:92
LLVM_ABI const ClassLayout & getUDTLayout() const
Definition: UDTLayout.cpp:94
IPDBRawSymbol defines an interface used to represent an arbitrary symbol.
Definition: IPDBRawSymbol.h:47
virtual uint64_t getLength() const =0
virtual SymIndexId getTypeId() const =0
IPDBSession defines an interface used to provide a context for querying debug information from a debu...
Definition: IPDBSession.h:26
virtual std::unique_ptr< PDBSymbol > getSymbolById(SymIndexId SymbolId) const =0
virtual uint32_t tailPadding() const
Definition: UDTLayout.cpp:63
uint32_t deepPaddingSize() const
Definition: UDTLayout.cpp:59
uint32_t getOffsetInParent() const
Definition: UDTLayout.h:49
LayoutItemBase(const UDTLayoutBase *Parent, const PDBSymbol *Symbol, const std::string &Name, uint32_t OffsetInParent, uint32_t Size, bool IsElided)
Definition: UDTLayout.cpp:49
const UDTLayoutBase * Parent
Definition: UDTLayout.h:65
const PDBSymbol * Symbol
Definition: UDTLayout.h:64
PDBSymbol defines the base of the inheritance hierarchy for concrete symbol types (e....
Definition: PDBSymbol.h:72
ArrayRef< BaseClassLayout * > VirtualBases
Definition: UDTLayout.h:148
bool hasVBPtrAtOffset(uint32_t Off) const
Definition: UDTLayout.cpp:269
std::vector< LayoutItemBase * > LayoutItems
Definition: UDTLayout.h:144
UniquePtrVector< PDBSymbol > Other
Definition: UDTLayout.h:141
uint32_t tailPadding() const override
Definition: UDTLayout.cpp:119
void addChildToLayout(std::unique_ptr< LayoutItemBase > Child)
Definition: UDTLayout.cpp:279
std::vector< BaseClassLayout * > AllBases
Definition: UDTLayout.h:146
UniquePtrVector< PDBSymbolFunc > Funcs
Definition: UDTLayout.h:142
VTableLayoutItem * VTable
Definition: UDTLayout.h:150
void initializeChildren(const PDBSymbol &Sym)
Definition: UDTLayout.cpp:167
UniquePtrVector< LayoutItemBase > ChildStorage
Definition: UDTLayout.h:143
ArrayRef< BaseClassLayout * > NonVirtualBases
Definition: UDTLayout.h:147
UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym, const std::string &Name, uint32_t OffsetInParent, uint32_t Size, bool IsElided)
Definition: UDTLayout.cpp:106
VBPtrLayoutItem * VBPtr
Definition: UDTLayout.h:151
LLVM_ABI VBPtrLayoutItem(const UDTLayoutBase &Parent, std::unique_ptr< PDBSymbolTypeBuiltin > Sym, uint32_t Offset, uint32_t Size)
Definition: UDTLayout.cpp:81
LLVM_ABI VTableLayoutItem(const UDTLayoutBase &Parent, std::unique_ptr< PDBSymbolTypeVTable > VTable)
Definition: UDTLayout.cpp:98
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto upper_bound(R &&Range, T &&Value)
Provide wrappers to std::upper_bound which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:2026
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1886
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:856