10b57cec5SDimitry Andric //===- UDTLayout.cpp ------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/UDTLayout.h"
100b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
110b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
120b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
1381ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
1481ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
150b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/IPDBSession.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbol.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
190b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
200b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
210b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
2281ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
230b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
240b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
250b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
260b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/PDBTypes.h"
270b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
280b57cec5SDimitry Andric #include <algorithm>
290b57cec5SDimitry Andric #include <cassert>
300b57cec5SDimitry Andric #include <cstdint>
310b57cec5SDimitry Andric #include <memory>
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric using namespace llvm;
340b57cec5SDimitry Andric using namespace llvm::pdb;
350b57cec5SDimitry Andric
getSymbolType(const PDBSymbol & Symbol)360b57cec5SDimitry Andric static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) {
370b57cec5SDimitry Andric const IPDBSession &Session = Symbol.getSession();
380b57cec5SDimitry Andric const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol();
390b57cec5SDimitry Andric uint32_t TypeId = RawSymbol.getTypeId();
400b57cec5SDimitry Andric return Session.getSymbolById(TypeId);
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
getTypeLength(const PDBSymbol & Symbol)430b57cec5SDimitry Andric static uint32_t getTypeLength(const PDBSymbol &Symbol) {
440b57cec5SDimitry Andric auto SymbolType = getSymbolType(Symbol);
450b57cec5SDimitry Andric const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric return RawType.getLength();
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
LayoutItemBase(const UDTLayoutBase * Parent,const PDBSymbol * Symbol,const std::string & Name,uint32_t OffsetInParent,uint32_t Size,bool IsElided)500b57cec5SDimitry Andric LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent,
510b57cec5SDimitry Andric const PDBSymbol *Symbol, const std::string &Name,
520b57cec5SDimitry Andric uint32_t OffsetInParent, uint32_t Size,
530b57cec5SDimitry Andric bool IsElided)
540b57cec5SDimitry Andric : Symbol(Symbol), Parent(Parent), Name(Name),
550b57cec5SDimitry Andric OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size),
560b57cec5SDimitry Andric IsElided(IsElided) {
570b57cec5SDimitry Andric UsedBytes.resize(SizeOf, true);
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
deepPaddingSize() const600b57cec5SDimitry Andric uint32_t LayoutItemBase::deepPaddingSize() const {
610b57cec5SDimitry Andric return UsedBytes.size() - UsedBytes.count();
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric
tailPadding() const640b57cec5SDimitry Andric uint32_t LayoutItemBase::tailPadding() const {
650b57cec5SDimitry Andric int Last = UsedBytes.find_last();
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric return UsedBytes.size() - (Last + 1);
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric
DataMemberLayoutItem(const UDTLayoutBase & Parent,std::unique_ptr<PDBSymbolData> Member)700b57cec5SDimitry Andric DataMemberLayoutItem::DataMemberLayoutItem(
710b57cec5SDimitry Andric const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member)
720b57cec5SDimitry Andric : LayoutItemBase(&Parent, Member.get(), Member->getName(),
730b57cec5SDimitry Andric Member->getOffset(), getTypeLength(*Member), false),
740b57cec5SDimitry Andric DataMember(std::move(Member)) {
750b57cec5SDimitry Andric auto Type = DataMember->getType();
760b57cec5SDimitry Andric if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) {
778bcb0991SDimitry Andric UdtLayout = std::make_unique<ClassLayout>(std::move(UDT));
780b57cec5SDimitry Andric UsedBytes = UdtLayout->usedBytes();
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
VBPtrLayoutItem(const UDTLayoutBase & Parent,std::unique_ptr<PDBSymbolTypeBuiltin> Sym,uint32_t Offset,uint32_t Size)820b57cec5SDimitry Andric VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent,
830b57cec5SDimitry Andric std::unique_ptr<PDBSymbolTypeBuiltin> Sym,
840b57cec5SDimitry Andric uint32_t Offset, uint32_t Size)
850b57cec5SDimitry Andric : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false),
860b57cec5SDimitry Andric Type(std::move(Sym)) {
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric
getDataMember()890b57cec5SDimitry Andric const PDBSymbolData &DataMemberLayoutItem::getDataMember() {
908bcb0991SDimitry Andric return *cast<PDBSymbolData>(Symbol);
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric
hasUDTLayout() const930b57cec5SDimitry Andric bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; }
940b57cec5SDimitry Andric
getUDTLayout() const950b57cec5SDimitry Andric const ClassLayout &DataMemberLayoutItem::getUDTLayout() const {
960b57cec5SDimitry Andric return *UdtLayout;
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric
VTableLayoutItem(const UDTLayoutBase & Parent,std::unique_ptr<PDBSymbolTypeVTable> VT)990b57cec5SDimitry Andric VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,
1000b57cec5SDimitry Andric std::unique_ptr<PDBSymbolTypeVTable> VT)
1010b57cec5SDimitry Andric : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false),
1020b57cec5SDimitry Andric VTable(std::move(VT)) {
1030b57cec5SDimitry Andric auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType());
1040b57cec5SDimitry Andric ElementSize = VTableType->getLength();
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric
UDTLayoutBase(const UDTLayoutBase * Parent,const PDBSymbol & Sym,const std::string & Name,uint32_t OffsetInParent,uint32_t Size,bool IsElided)1070b57cec5SDimitry Andric UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym,
1080b57cec5SDimitry Andric const std::string &Name, uint32_t OffsetInParent,
1090b57cec5SDimitry Andric uint32_t Size, bool IsElided)
1100b57cec5SDimitry Andric : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) {
1110b57cec5SDimitry Andric // UDT storage comes from a union of all the children's storage, so start out
1120b57cec5SDimitry Andric // uninitialized.
1130b57cec5SDimitry Andric UsedBytes.reset(0, Size);
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric initializeChildren(Sym);
1160b57cec5SDimitry Andric if (LayoutSize < Size)
1170b57cec5SDimitry Andric UsedBytes.resize(LayoutSize);
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric
tailPadding() const1200b57cec5SDimitry Andric uint32_t UDTLayoutBase::tailPadding() const {
1210b57cec5SDimitry Andric uint32_t Abs = LayoutItemBase::tailPadding();
1220b57cec5SDimitry Andric if (!LayoutItems.empty()) {
1230b57cec5SDimitry Andric const LayoutItemBase *Back = LayoutItems.back();
1240b57cec5SDimitry Andric uint32_t ChildPadding = Back->LayoutItemBase::tailPadding();
1250b57cec5SDimitry Andric if (Abs < ChildPadding)
1260b57cec5SDimitry Andric Abs = 0;
1270b57cec5SDimitry Andric else
1280b57cec5SDimitry Andric Abs -= ChildPadding;
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric return Abs;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric
ClassLayout(const PDBSymbolTypeUDT & UDT)1330b57cec5SDimitry Andric ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT)
1340b57cec5SDimitry Andric : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false),
1350b57cec5SDimitry Andric UDT(UDT) {
1360b57cec5SDimitry Andric ImmediateUsedBytes.resize(SizeOf, false);
1370b57cec5SDimitry Andric for (auto &LI : LayoutItems) {
1380b57cec5SDimitry Andric uint32_t Begin = LI->getOffsetInParent();
1390b57cec5SDimitry Andric uint32_t End = Begin + LI->getLayoutSize();
1400b57cec5SDimitry Andric End = std::min(SizeOf, End);
1410b57cec5SDimitry Andric ImmediateUsedBytes.set(Begin, End);
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)1450b57cec5SDimitry Andric ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)
1460b57cec5SDimitry Andric : ClassLayout(*UDT) {
1470b57cec5SDimitry Andric OwnedStorage = std::move(UDT);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric
immediatePadding() const1500b57cec5SDimitry Andric uint32_t ClassLayout::immediatePadding() const {
1510b57cec5SDimitry Andric return SizeOf - ImmediateUsedBytes.count();
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric
BaseClassLayout(const UDTLayoutBase & Parent,uint32_t OffsetInParent,bool Elide,std::unique_ptr<PDBSymbolTypeBaseClass> B)1540b57cec5SDimitry Andric BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent,
1550b57cec5SDimitry Andric uint32_t OffsetInParent, bool Elide,
1560b57cec5SDimitry Andric std::unique_ptr<PDBSymbolTypeBaseClass> B)
1570b57cec5SDimitry Andric : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(),
1580b57cec5SDimitry Andric Elide),
1590b57cec5SDimitry Andric Base(std::move(B)) {
1600b57cec5SDimitry Andric if (isEmptyBase()) {
1610b57cec5SDimitry Andric // Special case an empty base so that it doesn't get treated as padding.
1620b57cec5SDimitry Andric UsedBytes.resize(1);
1630b57cec5SDimitry Andric UsedBytes.set(0);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric IsVirtualBase = Base->isVirtualBaseClass();
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
initializeChildren(const PDBSymbol & Sym)1680b57cec5SDimitry Andric void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) {
1690b57cec5SDimitry Andric // Handled bases first, followed by VTables, followed by data members,
1700b57cec5SDimitry Andric // followed by functions, followed by other. This ordering is necessary
1710b57cec5SDimitry Andric // so that bases and vtables get initialized before any functions which
1720b57cec5SDimitry Andric // may override them.
1730b57cec5SDimitry Andric UniquePtrVector<PDBSymbolTypeBaseClass> Bases;
1740b57cec5SDimitry Andric UniquePtrVector<PDBSymbolTypeVTable> VTables;
1750b57cec5SDimitry Andric UniquePtrVector<PDBSymbolData> Members;
1760b57cec5SDimitry Andric UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms;
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric auto Children = Sym.findAllChildren();
1790b57cec5SDimitry Andric while (auto Child = Children->getNext()) {
1800b57cec5SDimitry Andric if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
1810b57cec5SDimitry Andric if (Base->isVirtualBaseClass())
1820b57cec5SDimitry Andric VirtualBaseSyms.push_back(std::move(Base));
1830b57cec5SDimitry Andric else
1840b57cec5SDimitry Andric Bases.push_back(std::move(Base));
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) {
1870b57cec5SDimitry Andric if (Data->getDataKind() == PDB_DataKind::Member)
1880b57cec5SDimitry Andric Members.push_back(std::move(Data));
1890b57cec5SDimitry Andric else
1900b57cec5SDimitry Andric Other.push_back(std::move(Data));
1910b57cec5SDimitry Andric } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child))
1920b57cec5SDimitry Andric VTables.push_back(std::move(VT));
1930b57cec5SDimitry Andric else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child))
1940b57cec5SDimitry Andric Funcs.push_back(std::move(Func));
1950b57cec5SDimitry Andric else {
1960b57cec5SDimitry Andric Other.push_back(std::move(Child));
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric // We don't want to have any re-allocations in the list of bases, so make
2010b57cec5SDimitry Andric // sure to reserve enough space so that our ArrayRefs don't get invalidated.
2020b57cec5SDimitry Andric AllBases.reserve(Bases.size() + VirtualBaseSyms.size());
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric // Only add non-virtual bases to the class first. Only at the end of the
2050b57cec5SDimitry Andric // class, after all non-virtual bases and data members have been added do we
2060b57cec5SDimitry Andric // add virtual bases. This way the offsets are correctly aligned when we go
2070b57cec5SDimitry Andric // to lay out virtual bases.
2080b57cec5SDimitry Andric for (auto &Base : Bases) {
2090b57cec5SDimitry Andric uint32_t Offset = Base->getOffset();
2100b57cec5SDimitry Andric // Non-virtual bases never get elided.
2118bcb0991SDimitry Andric auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false,
2120b57cec5SDimitry Andric std::move(Base));
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric AllBases.push_back(BL.get());
2150b57cec5SDimitry Andric addChildToLayout(std::move(BL));
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric NonVirtualBases = AllBases;
2180b57cec5SDimitry Andric
2190b57cec5SDimitry Andric assert(VTables.size() <= 1);
2200b57cec5SDimitry Andric if (!VTables.empty()) {
2210b57cec5SDimitry Andric auto VTLayout =
2228bcb0991SDimitry Andric std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0]));
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric VTable = VTLayout.get();
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric addChildToLayout(std::move(VTLayout));
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric for (auto &Data : Members) {
2308bcb0991SDimitry Andric auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data));
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric addChildToLayout(std::move(DM));
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric
2350b57cec5SDimitry Andric // Make sure add virtual bases before adding functions, since functions may be
2360b57cec5SDimitry Andric // overrides of virtual functions declared in a virtual base, so the VTables
2370b57cec5SDimitry Andric // and virtual intros need to be correctly initialized.
2380b57cec5SDimitry Andric for (auto &VB : VirtualBaseSyms) {
2390b57cec5SDimitry Andric int VBPO = VB->getVirtualBasePointerOffset();
2400b57cec5SDimitry Andric if (!hasVBPtrAtOffset(VBPO)) {
2410b57cec5SDimitry Andric if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) {
2428bcb0991SDimitry Andric auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP),
2430b57cec5SDimitry Andric VBPO, VBP->getLength());
2440b57cec5SDimitry Andric VBPtr = VBPL.get();
2450b57cec5SDimitry Andric addChildToLayout(std::move(VBPL));
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric
2490b57cec5SDimitry Andric // Virtual bases always go at the end. So just look for the last place we
2500b57cec5SDimitry Andric // ended when writing something, and put our virtual base there.
2510b57cec5SDimitry Andric // Note that virtual bases get elided unless this is a top-most derived
2520b57cec5SDimitry Andric // class.
2530b57cec5SDimitry Andric uint32_t Offset = UsedBytes.find_last() + 1;
2540b57cec5SDimitry Andric bool Elide = (Parent != nullptr);
2550b57cec5SDimitry Andric auto BL =
2568bcb0991SDimitry Andric std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB));
2570b57cec5SDimitry Andric AllBases.push_back(BL.get());
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric // Only lay this virtual base out directly inside of *this* class if this
2600b57cec5SDimitry Andric // is a top-most derived class. Keep track of it regardless, but only
2610b57cec5SDimitry Andric // physically lay it out if it's a topmost derived class.
2620b57cec5SDimitry Andric addChildToLayout(std::move(BL));
2630b57cec5SDimitry Andric }
264*bdd1243dSDimitry Andric VirtualBases = ArrayRef(AllBases).drop_front(NonVirtualBases.size());
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andric if (Parent != nullptr)
2670b57cec5SDimitry Andric LayoutSize = UsedBytes.find_last() + 1;
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric
hasVBPtrAtOffset(uint32_t Off) const2700b57cec5SDimitry Andric bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const {
2710b57cec5SDimitry Andric if (VBPtr && VBPtr->getOffsetInParent() == Off)
2720b57cec5SDimitry Andric return true;
2730b57cec5SDimitry Andric for (BaseClassLayout *BL : AllBases) {
2740b57cec5SDimitry Andric if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent()))
2750b57cec5SDimitry Andric return true;
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric return false;
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric
addChildToLayout(std::unique_ptr<LayoutItemBase> Child)2800b57cec5SDimitry Andric void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) {
2810b57cec5SDimitry Andric uint32_t Begin = Child->getOffsetInParent();
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric if (!Child->isElided()) {
2840b57cec5SDimitry Andric BitVector ChildBytes = Child->usedBytes();
2850b57cec5SDimitry Andric
2860b57cec5SDimitry Andric // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte
2870b57cec5SDimitry Andric // class. When we call ChildBytes.resize(32), the Child's storage will
2880b57cec5SDimitry Andric // still begin at offset 0, so we need to shift it left by offset bytes
2890b57cec5SDimitry Andric // to get it into the right position.
2900b57cec5SDimitry Andric ChildBytes.resize(UsedBytes.size());
2910b57cec5SDimitry Andric ChildBytes <<= Child->getOffsetInParent();
2920b57cec5SDimitry Andric UsedBytes |= ChildBytes;
2930b57cec5SDimitry Andric
2940b57cec5SDimitry Andric if (ChildBytes.count() > 0) {
295e8d8bef9SDimitry Andric auto Loc = llvm::upper_bound(
296e8d8bef9SDimitry Andric LayoutItems, Begin, [](uint32_t Off, const LayoutItemBase *Item) {
2970b57cec5SDimitry Andric return (Off < Item->getOffsetInParent());
2980b57cec5SDimitry Andric });
2990b57cec5SDimitry Andric
3000b57cec5SDimitry Andric LayoutItems.insert(Loc, Child.get());
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric }
3030b57cec5SDimitry Andric
3040b57cec5SDimitry Andric ChildStorage.push_back(std::move(Child));
3050b57cec5SDimitry Andric }
306