Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/UDTLayout.cpp
35266 views
//===- UDTLayout.cpp ------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DebugInfo/PDB/UDTLayout.h"9#include "llvm/ADT/ArrayRef.h"10#include "llvm/ADT/BitVector.h"11#include "llvm/ADT/STLExtras.h"12#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"13#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"14#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"15#include "llvm/DebugInfo/PDB/IPDBSession.h"16#include "llvm/DebugInfo/PDB/PDBSymbol.h"17#include "llvm/DebugInfo/PDB/PDBSymbolData.h"18#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"19#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"20#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"21#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"22#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"23#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"24#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"25#include "llvm/DebugInfo/PDB/PDBTypes.h"26#include "llvm/Support/Casting.h"27#include <algorithm>28#include <cassert>29#include <cstdint>30#include <memory>3132using namespace llvm;33using namespace llvm::pdb;3435static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) {36const IPDBSession &Session = Symbol.getSession();37const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol();38uint32_t TypeId = RawSymbol.getTypeId();39return Session.getSymbolById(TypeId);40}4142static uint32_t getTypeLength(const PDBSymbol &Symbol) {43auto SymbolType = getSymbolType(Symbol);44const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();4546return RawType.getLength();47}4849LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent,50const PDBSymbol *Symbol, const std::string &Name,51uint32_t OffsetInParent, uint32_t Size,52bool IsElided)53: Symbol(Symbol), Parent(Parent), Name(Name),54OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size),55IsElided(IsElided) {56UsedBytes.resize(SizeOf, true);57}5859uint32_t LayoutItemBase::deepPaddingSize() const {60return UsedBytes.size() - UsedBytes.count();61}6263uint32_t LayoutItemBase::tailPadding() const {64int Last = UsedBytes.find_last();6566return UsedBytes.size() - (Last + 1);67}6869DataMemberLayoutItem::DataMemberLayoutItem(70const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member)71: LayoutItemBase(&Parent, Member.get(), Member->getName(),72Member->getOffset(), getTypeLength(*Member), false),73DataMember(std::move(Member)) {74auto Type = DataMember->getType();75if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) {76UdtLayout = std::make_unique<ClassLayout>(std::move(UDT));77UsedBytes = UdtLayout->usedBytes();78}79}8081VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent,82std::unique_ptr<PDBSymbolTypeBuiltin> Sym,83uint32_t Offset, uint32_t Size)84: LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false),85Type(std::move(Sym)) {86}8788const PDBSymbolData &DataMemberLayoutItem::getDataMember() {89return *cast<PDBSymbolData>(Symbol);90}9192bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; }9394const ClassLayout &DataMemberLayoutItem::getUDTLayout() const {95return *UdtLayout;96}9798VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,99std::unique_ptr<PDBSymbolTypeVTable> VT)100: LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false),101VTable(std::move(VT)) {102auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType());103ElementSize = VTableType->getLength();104}105106UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym,107const std::string &Name, uint32_t OffsetInParent,108uint32_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 out111// uninitialized.112UsedBytes.reset(0, Size);113114initializeChildren(Sym);115if (LayoutSize < Size)116UsedBytes.resize(LayoutSize);117}118119uint32_t UDTLayoutBase::tailPadding() const {120uint32_t Abs = LayoutItemBase::tailPadding();121if (!LayoutItems.empty()) {122const LayoutItemBase *Back = LayoutItems.back();123uint32_t ChildPadding = Back->LayoutItemBase::tailPadding();124if (Abs < ChildPadding)125Abs = 0;126else127Abs -= ChildPadding;128}129return Abs;130}131132ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT)133: UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false),134UDT(UDT) {135ImmediateUsedBytes.resize(SizeOf, false);136for (auto &LI : LayoutItems) {137uint32_t Begin = LI->getOffsetInParent();138uint32_t End = Begin + LI->getLayoutSize();139End = std::min(SizeOf, End);140ImmediateUsedBytes.set(Begin, End);141}142}143144ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)145: ClassLayout(*UDT) {146OwnedStorage = std::move(UDT);147}148149uint32_t ClassLayout::immediatePadding() const {150return SizeOf - ImmediateUsedBytes.count();151}152153BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent,154uint32_t OffsetInParent, bool Elide,155std::unique_ptr<PDBSymbolTypeBaseClass> B)156: UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(),157Elide),158Base(std::move(B)) {159if (isEmptyBase()) {160// Special case an empty base so that it doesn't get treated as padding.161UsedBytes.resize(1);162UsedBytes.set(0);163}164IsVirtualBase = Base->isVirtualBaseClass();165}166167void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) {168// Handled bases first, followed by VTables, followed by data members,169// followed by functions, followed by other. This ordering is necessary170// so that bases and vtables get initialized before any functions which171// may override them.172UniquePtrVector<PDBSymbolTypeBaseClass> Bases;173UniquePtrVector<PDBSymbolTypeVTable> VTables;174UniquePtrVector<PDBSymbolData> Members;175UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms;176177auto Children = Sym.findAllChildren();178while (auto Child = Children->getNext()) {179if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {180if (Base->isVirtualBaseClass())181VirtualBaseSyms.push_back(std::move(Base));182else183Bases.push_back(std::move(Base));184}185else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) {186if (Data->getDataKind() == PDB_DataKind::Member)187Members.push_back(std::move(Data));188else189Other.push_back(std::move(Data));190} else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child))191VTables.push_back(std::move(VT));192else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child))193Funcs.push_back(std::move(Func));194else {195Other.push_back(std::move(Child));196}197}198199// We don't want to have any re-allocations in the list of bases, so make200// sure to reserve enough space so that our ArrayRefs don't get invalidated.201AllBases.reserve(Bases.size() + VirtualBaseSyms.size());202203// Only add non-virtual bases to the class first. Only at the end of the204// class, after all non-virtual bases and data members have been added do we205// add virtual bases. This way the offsets are correctly aligned when we go206// to lay out virtual bases.207for (auto &Base : Bases) {208uint32_t Offset = Base->getOffset();209// Non-virtual bases never get elided.210auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false,211std::move(Base));212213AllBases.push_back(BL.get());214addChildToLayout(std::move(BL));215}216NonVirtualBases = AllBases;217218assert(VTables.size() <= 1);219if (!VTables.empty()) {220auto VTLayout =221std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0]));222223VTable = VTLayout.get();224225addChildToLayout(std::move(VTLayout));226}227228for (auto &Data : Members) {229auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data));230231addChildToLayout(std::move(DM));232}233234// Make sure add virtual bases before adding functions, since functions may be235// overrides of virtual functions declared in a virtual base, so the VTables236// and virtual intros need to be correctly initialized.237for (auto &VB : VirtualBaseSyms) {238int VBPO = VB->getVirtualBasePointerOffset();239if (!hasVBPtrAtOffset(VBPO)) {240if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) {241auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP),242VBPO, VBP->getLength());243VBPtr = VBPL.get();244addChildToLayout(std::move(VBPL));245}246}247248// Virtual bases always go at the end. So just look for the last place we249// ended when writing something, and put our virtual base there.250// Note that virtual bases get elided unless this is a top-most derived251// class.252uint32_t Offset = UsedBytes.find_last() + 1;253bool Elide = (Parent != nullptr);254auto BL =255std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB));256AllBases.push_back(BL.get());257258// Only lay this virtual base out directly inside of *this* class if this259// is a top-most derived class. Keep track of it regardless, but only260// physically lay it out if it's a topmost derived class.261addChildToLayout(std::move(BL));262}263VirtualBases = ArrayRef(AllBases).drop_front(NonVirtualBases.size());264265if (Parent != nullptr)266LayoutSize = UsedBytes.find_last() + 1;267}268269bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const {270if (VBPtr && VBPtr->getOffsetInParent() == Off)271return true;272for (BaseClassLayout *BL : AllBases) {273if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent()))274return true;275}276return false;277}278279void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) {280uint32_t Begin = Child->getOffsetInParent();281282if (!Child->isElided()) {283BitVector ChildBytes = Child->usedBytes();284285// Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte286// class. When we call ChildBytes.resize(32), the Child's storage will287// still begin at offset 0, so we need to shift it left by offset bytes288// to get it into the right position.289ChildBytes.resize(UsedBytes.size());290ChildBytes <<= Child->getOffsetInParent();291UsedBytes |= ChildBytes;292293if (ChildBytes.count() > 0) {294auto Loc = llvm::upper_bound(295LayoutItems, Begin, [](uint32_t Off, const LayoutItemBase *Item) {296return (Off < Item->getOffsetInParent());297});298299LayoutItems.insert(Loc, Child.get());300}301}302303ChildStorage.push_back(std::move(Child));304}305306307