diff options
Diffstat (limited to 'llvm/lib/DebugInfo/PDB/UDTLayout.cpp')
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/UDTLayout.cpp | 302 | 
1 files changed, 302 insertions, 0 deletions
| diff --git a/llvm/lib/DebugInfo/PDB/UDTLayout.cpp b/llvm/lib/DebugInfo/PDB/UDTLayout.cpp new file mode 100644 index 0000000000000..a8e1d0a619cab --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/UDTLayout.cpp @@ -0,0 +1,302 @@ +//===- UDTLayout.cpp ------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/Casting.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <memory> + +using namespace llvm; +using namespace llvm::pdb; + +static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) { +  const IPDBSession &Session = Symbol.getSession(); +  const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol(); +  uint32_t TypeId = RawSymbol.getTypeId(); +  return Session.getSymbolById(TypeId); +} + +static uint32_t getTypeLength(const PDBSymbol &Symbol) { +  auto SymbolType = getSymbolType(Symbol); +  const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); + +  return RawType.getLength(); +} + +LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent, +                               const PDBSymbol *Symbol, const std::string &Name, +                               uint32_t OffsetInParent, uint32_t Size, +                               bool IsElided) +    : Symbol(Symbol), Parent(Parent), Name(Name), +      OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size), +      IsElided(IsElided) { +  UsedBytes.resize(SizeOf, true); +} + +uint32_t LayoutItemBase::deepPaddingSize() const { +  return UsedBytes.size() - UsedBytes.count(); +} + +uint32_t LayoutItemBase::tailPadding() const { +  int Last = UsedBytes.find_last(); + +  return UsedBytes.size() - (Last + 1); +} + +DataMemberLayoutItem::DataMemberLayoutItem( +    const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member) +    : LayoutItemBase(&Parent, Member.get(), Member->getName(), +                     Member->getOffset(), getTypeLength(*Member), false), +      DataMember(std::move(Member)) { +  auto Type = DataMember->getType(); +  if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) { +    UdtLayout = std::make_unique<ClassLayout>(std::move(UDT)); +    UsedBytes = UdtLayout->usedBytes(); +  } +} + +VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent, +                                 std::unique_ptr<PDBSymbolTypeBuiltin> Sym, +                                 uint32_t Offset, uint32_t Size) +    : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false), +      Type(std::move(Sym)) { +} + +const PDBSymbolData &DataMemberLayoutItem::getDataMember() { +  return *cast<PDBSymbolData>(Symbol); +} + +bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; } + +const ClassLayout &DataMemberLayoutItem::getUDTLayout() const { +  return *UdtLayout; +} + +VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, +                                   std::unique_ptr<PDBSymbolTypeVTable> VT) +    : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false), +      VTable(std::move(VT)) { +  auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType()); +  ElementSize = VTableType->getLength(); +} + +UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym, +                             const std::string &Name, uint32_t OffsetInParent, +                             uint32_t Size, bool IsElided) +    : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) { +  // UDT storage comes from a union of all the children's storage, so start out +  // uninitialized. +  UsedBytes.reset(0, Size); + +  initializeChildren(Sym); +  if (LayoutSize < Size) +    UsedBytes.resize(LayoutSize); +} + +uint32_t UDTLayoutBase::tailPadding() const { +  uint32_t Abs = LayoutItemBase::tailPadding(); +  if (!LayoutItems.empty()) { +    const LayoutItemBase *Back = LayoutItems.back(); +    uint32_t ChildPadding = Back->LayoutItemBase::tailPadding(); +    if (Abs < ChildPadding) +      Abs = 0; +    else +      Abs -= ChildPadding; +  } +  return Abs; +} + +ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT) +    : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false), +      UDT(UDT) { +  ImmediateUsedBytes.resize(SizeOf, false); +  for (auto &LI : LayoutItems) { +    uint32_t Begin = LI->getOffsetInParent(); +    uint32_t End = Begin + LI->getLayoutSize(); +    End = std::min(SizeOf, End); +    ImmediateUsedBytes.set(Begin, End); +  } +} + +ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT) +    : ClassLayout(*UDT) { +  OwnedStorage = std::move(UDT); +} + +uint32_t ClassLayout::immediatePadding() const { +  return SizeOf - ImmediateUsedBytes.count(); +} + +BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent, +                                 uint32_t OffsetInParent, bool Elide, +                                 std::unique_ptr<PDBSymbolTypeBaseClass> B) +    : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(), +                    Elide), +      Base(std::move(B)) { +  if (isEmptyBase()) { +    // Special case an empty base so that it doesn't get treated as padding. +    UsedBytes.resize(1); +    UsedBytes.set(0); +  } +  IsVirtualBase = Base->isVirtualBaseClass(); +} + +void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { +  // Handled bases first, followed by VTables, followed by data members, +  // followed by functions, followed by other.  This ordering is necessary +  // so that bases and vtables get initialized before any functions which +  // may override them. +  UniquePtrVector<PDBSymbolTypeBaseClass> Bases; +  UniquePtrVector<PDBSymbolTypeVTable> VTables; +  UniquePtrVector<PDBSymbolData> Members; +  UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms; + +  auto Children = Sym.findAllChildren(); +  while (auto Child = Children->getNext()) { +    if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) { +      if (Base->isVirtualBaseClass()) +        VirtualBaseSyms.push_back(std::move(Base)); +      else +        Bases.push_back(std::move(Base)); +    } +    else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) { +      if (Data->getDataKind() == PDB_DataKind::Member) +        Members.push_back(std::move(Data)); +      else +        Other.push_back(std::move(Data)); +    } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) +      VTables.push_back(std::move(VT)); +    else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child)) +      Funcs.push_back(std::move(Func)); +    else { +      Other.push_back(std::move(Child)); +    } +  } + +  // We don't want to have any re-allocations in the list of bases, so make +  // sure to reserve enough space so that our ArrayRefs don't get invalidated. +  AllBases.reserve(Bases.size() + VirtualBaseSyms.size()); + +  // Only add non-virtual bases to the class first.  Only at the end of the +  // class, after all non-virtual bases and data members have been added do we +  // add virtual bases.  This way the offsets are correctly aligned when we go +  // to lay out virtual bases. +  for (auto &Base : Bases) { +    uint32_t Offset = Base->getOffset(); +    // Non-virtual bases never get elided. +    auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false, +                                                 std::move(Base)); + +    AllBases.push_back(BL.get()); +    addChildToLayout(std::move(BL)); +  } +  NonVirtualBases = AllBases; + +  assert(VTables.size() <= 1); +  if (!VTables.empty()) { +    auto VTLayout = +        std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0])); + +    VTable = VTLayout.get(); + +    addChildToLayout(std::move(VTLayout)); +  } + +  for (auto &Data : Members) { +    auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data)); + +    addChildToLayout(std::move(DM)); +  } + +  // Make sure add virtual bases before adding functions, since functions may be +  // overrides of virtual functions declared in a virtual base, so the VTables +  // and virtual intros need to be correctly initialized. +  for (auto &VB : VirtualBaseSyms) { +    int VBPO = VB->getVirtualBasePointerOffset(); +    if (!hasVBPtrAtOffset(VBPO)) { +      if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) { +        auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP), +                                                       VBPO, VBP->getLength()); +        VBPtr = VBPL.get(); +        addChildToLayout(std::move(VBPL)); +      } +    } + +    // Virtual bases always go at the end.  So just look for the last place we +    // ended when writing something, and put our virtual base there. +    // Note that virtual bases get elided unless this is a top-most derived +    // class. +    uint32_t Offset = UsedBytes.find_last() + 1; +    bool Elide = (Parent != nullptr); +    auto BL = +        std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB)); +    AllBases.push_back(BL.get()); + +    // Only lay this virtual base out directly inside of *this* class if this +    // is a top-most derived class.  Keep track of it regardless, but only +    // physically lay it out if it's a topmost derived class. +    addChildToLayout(std::move(BL)); +  } +  VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size()); + +  if (Parent != nullptr) +    LayoutSize = UsedBytes.find_last() + 1; +} + +bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const { +  if (VBPtr && VBPtr->getOffsetInParent() == Off) +    return true; +  for (BaseClassLayout *BL : AllBases) { +    if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent())) +      return true; +  } +  return false; +} + +void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) { +  uint32_t Begin = Child->getOffsetInParent(); + +  if (!Child->isElided()) { +    BitVector ChildBytes = Child->usedBytes(); + +    // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte +    // class.  When we call ChildBytes.resize(32), the Child's storage will +    // still begin at offset 0, so we need to shift it left by offset bytes +    // to get it into the right position. +    ChildBytes.resize(UsedBytes.size()); +    ChildBytes <<= Child->getOffsetInParent(); +    UsedBytes |= ChildBytes; + +    if (ChildBytes.count() > 0) { +      auto Loc = std::upper_bound(LayoutItems.begin(), LayoutItems.end(), Begin, +                                  [](uint32_t Off, const LayoutItemBase *Item) { +                                    return (Off < Item->getOffsetInParent()); +                                  }); + +      LayoutItems.insert(Loc, Child.get()); +    } +  } + +  ChildStorage.push_back(std::move(Child)); +} | 
