mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-25 14:28:54 -04:00

to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
303 lines
11 KiB
C++
303 lines
11 KiB
C++
//===- 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 = llvm::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 *dyn_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 = llvm::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 =
|
|
llvm::make_unique<VTableLayoutItem>(*this, std::move(VTables[0]));
|
|
|
|
VTable = VTLayout.get();
|
|
|
|
addChildToLayout(std::move(VTLayout));
|
|
}
|
|
|
|
for (auto &Data : Members) {
|
|
auto DM = llvm::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 = llvm::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 =
|
|
llvm::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));
|
|
}
|