diff options
Diffstat (limited to 'llvm')
39 files changed, 769 insertions, 155 deletions
diff --git a/llvm/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h b/llvm/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h index 1e40c46f8a2..c0633cbdfa5 100644 --- a/llvm/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h +++ b/llvm/include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h @@ -102,6 +102,7 @@ public: uint32_t getVirtualBaseDispIndex() const override; uint32_t getVirtualBaseOffset() const override; uint32_t getVirtualTableShapeId() const override; + std::unique_ptr<PDBSymbolTypeVTable> getVirtualBaseTableType() const override; PDB_DataKind getDataKind() const override; PDB_SymType getSymTag() const override; PDB_UniqueId getGuid() const override; diff --git a/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h b/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h index 350442556be..3f5818631e7 100644 --- a/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ b/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -31,7 +31,7 @@ public: uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; - std::unique_ptr<PDBSymbolExe> getGlobalScope() override; + std::unique_ptr<PDBSymbolExe> getGlobalScope() const override; std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override; std::unique_ptr<PDBSymbol> diff --git a/llvm/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h b/llvm/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h index 49866b8bb2f..4c28e194bc7 100644 --- a/llvm/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h +++ b/llvm/include/llvm/DebugInfo/PDB/IPDBRawSymbol.h @@ -21,6 +21,9 @@ class raw_ostream; namespace pdb { +class PDBSymbolTypeVTable; +class PDBSymbolTypeVTableShape; + /// IPDBRawSymbol defines an interface used to represent an arbitrary symbol. /// It exposes a monolithic interface consisting of accessors for the union of /// all properties that are valid for any symbol type. This interface is then @@ -110,6 +113,8 @@ public: virtual Variant getValue() const = 0; virtual uint32_t getVirtualBaseDispIndex() const = 0; virtual uint32_t getVirtualBaseOffset() const = 0; + virtual std::unique_ptr<PDBSymbolTypeVTable> + getVirtualBaseTableType() const = 0; virtual uint32_t getVirtualTableShapeId() const = 0; virtual PDB_DataKind getDataKind() const = 0; virtual PDB_SymType getSymTag() const = 0; diff --git a/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h b/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h index 696736a907a..85d9fe12485 100644 --- a/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -29,20 +29,12 @@ public: virtual uint64_t getLoadAddress() const = 0; virtual void setLoadAddress(uint64_t Address) = 0; - virtual std::unique_ptr<PDBSymbolExe> getGlobalScope() = 0; + virtual std::unique_ptr<PDBSymbolExe> getGlobalScope() const = 0; virtual std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const = 0; template <typename T> std::unique_ptr<T> getConcreteSymbolById(uint32_t SymbolId) const { - auto Symbol(getSymbolById(SymbolId)); - if (!Symbol) - return nullptr; - - T *ConcreteSymbol = dyn_cast<T>(Symbol.get()); - if (!ConcreteSymbol) - return nullptr; - (void)Symbol.release(); - return std::unique_ptr<T>(ConcreteSymbol); + return unique_dyn_cast_or_null<T>(getSymbolById(SymbolId)); } virtual std::unique_ptr<PDBSymbol> diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h b/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h index 655bed9ac17..cffb5d09d22 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h @@ -101,6 +101,7 @@ public: uint32_t getVirtualBaseDispIndex() const override; uint32_t getVirtualBaseOffset() const override; uint32_t getVirtualTableShapeId() const override; + std::unique_ptr<PDBSymbolTypeVTable> getVirtualBaseTableType() const override; PDB_DataKind getDataKind() const override; PDB_SymType getSymTag() const override; PDB_UniqueId getGuid() const override; diff --git a/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h b/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h index bbe207738e0..e6da266f796 100644 --- a/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h +++ b/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h @@ -32,7 +32,7 @@ public: uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; - std::unique_ptr<PDBSymbolExe> getGlobalScope() override; + std::unique_ptr<PDBSymbolExe> getGlobalScope() const override; std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override; std::unique_ptr<PDBSymbol> diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h b/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h index 652f2136105..b114b7afb0b 100644 --- a/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h +++ b/llvm/include/llvm/DebugInfo/PDB/PDBSymbol.h @@ -62,6 +62,7 @@ class PDBSymbol { protected: PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol); + PDBSymbol(PDBSymbol &Symbol); public: static std::unique_ptr<PDBSymbol> @@ -91,12 +92,6 @@ public: return Enumerator->getNext(); } - template <typename T> T *cast() { return llvm::dyn_cast<T>(this); } - - template <typename T> const T *cast() const { - return llvm::dyn_cast<T>(this); - } - std::unique_ptr<PDBSymbol> clone() const; template <typename T> @@ -128,18 +123,11 @@ protected: template <typename ConcreteType> std::unique_ptr<ConcreteType> getConcreteSymbolByIdHelper(uint32_t Id) const { - auto Sym = getSymbolByIdHelper(Id); - if (!Sym) - return nullptr; - ConcreteType *Result = Sym->cast<ConcreteType>(); - if (!Result) - return nullptr; - Sym.release(); - return std::unique_ptr<ConcreteType>(Result); + return unique_dyn_cast_or_null<ConcreteType>(getSymbolByIdHelper(Id)); } const IPDBSession &Session; - const std::unique_ptr<IPDBRawSymbol> RawSymbol; + std::unique_ptr<IPDBRawSymbol> RawSymbol; }; } // namespace llvm diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolExe.h b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolExe.h index 5b3f50d153e..2c2d7466504 100644 --- a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolExe.h +++ b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolExe.h @@ -37,6 +37,8 @@ public: FORWARD_SYMBOL_METHOD(getSignature) FORWARD_SYMBOL_METHOD(getSymbolsFileName) + uint32_t getPointerByteSize() const; + private: void dumpChildren(raw_ostream &OS, StringRef Label, PDB_SymType ChildType, int Indent) const; diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h index 0924efb8aa9..d607a3d8117 100644 --- a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h +++ b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h @@ -13,6 +13,9 @@ #include "PDBSymbol.h" #include "PDBTypes.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" + namespace llvm { class raw_ostream; diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h index 47a4525a47b..e9e7fe8c986 100644 --- a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h +++ b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h @@ -10,7 +10,9 @@ #ifndef LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H #define LLVM_DEBUGINFO_PDB_PDBSYMBOLTYPEUDT_H +#include "IPDBSession.h" #include "PDBSymbol.h" +#include "PDBSymbolTypeBaseClass.h" #include "PDBTypes.h" namespace llvm { @@ -18,11 +20,17 @@ namespace llvm { class raw_ostream; namespace pdb { + class PDBSymbolTypeUDT : public PDBSymbol { public: PDBSymbolTypeUDT(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> UDTSymbol); + std::unique_ptr<PDBSymbolTypeUDT> clone() const { + return getSession().getConcreteSymbolById<PDBSymbolTypeUDT>( + getSymIndexId()); + } + DECLARE_PDB_SYMBOL_CONCRETE_TYPE(PDB_SymType::UDT) void dump(PDBSymDumper &Dumper) const override; diff --git a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h index 17612ff4606..e270c2b7eb9 100644 --- a/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h +++ b/llvm/include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h @@ -28,6 +28,7 @@ public: void dump(PDBSymDumper &Dumper) const override; FORWARD_SYMBOL_ID_METHOD(getClassParent) + FORWARD_SYMBOL_METHOD(getOffset) FORWARD_SYMBOL_METHOD(isConstType) FORWARD_SYMBOL_ID_METHOD(getLexicalParent) FORWARD_SYMBOL_ID_METHOD(getType) diff --git a/llvm/include/llvm/DebugInfo/PDB/UDTLayout.h b/llvm/include/llvm/DebugInfo/PDB/UDTLayout.h new file mode 100644 index 00000000000..20b70340f33 --- /dev/null +++ b/llvm/include/llvm/DebugInfo/PDB/UDTLayout.h @@ -0,0 +1,145 @@ +//===- UDTLayout.h - UDT layout info ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_UDTLAYOUT_H +#define LLVM_DEBUGINFO_PDB_UDTLAYOUT_H + +#include "PDBSymbol.h" +#include "PDBTypes.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" + +#include <list> +#include <memory> + +namespace llvm { + +class raw_ostream; + +namespace pdb { + +class PDBSymTypeBaseClass; +class PDBSymbolData; +class PDBSymbolTypeUDT; +class PDBSymbolTypeVTable; + +class ClassLayout; +class BaseClassLayout; +class StorageItemBase; +class UDTLayoutBase; + +class StorageItemBase { +public: + StorageItemBase(const UDTLayoutBase &Parent, const PDBSymbol &Symbol, + const std::string &Name, uint32_t OffsetInParent, + uint32_t Size); + virtual ~StorageItemBase() {} + + virtual uint32_t deepPaddingSize() const; + + const UDTLayoutBase &getParent() const { return Parent; } + StringRef getName() const { return Name; } + uint32_t getOffsetInParent() const { return OffsetInParent; } + uint32_t getSize() const { return SizeOf; } + const PDBSymbol &getSymbol() const { return Symbol; } + +protected: + const UDTLayoutBase &Parent; + const PDBSymbol &Symbol; + BitVector UsedBytes; + std::string Name; + uint32_t OffsetInParent = 0; + uint32_t SizeOf = 0; +}; + +class DataMemberLayoutItem : public StorageItemBase { +public: + DataMemberLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolData> DataMember); + + virtual uint32_t deepPaddingSize() const; + + const PDBSymbolData &getDataMember(); + +private: + std::unique_ptr<PDBSymbolData> DataMember; + std::unique_ptr<ClassLayout> UdtLayout; +}; + +class VTableLayoutItem : public StorageItemBase { +public: + VTableLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeVTable> VTable); + +private: + std::unique_ptr<PDBSymbolTypeVTable> VTable; + std::vector<std::unique_ptr<PDBSymbolFunc>> VTableFuncs; +}; + +class UDTLayoutBase { +public: + UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, + uint32_t Size); + + uint32_t shallowPaddingSize() const; + uint32_t deepPaddingSize() const; + + const BitVector &usedBytes() const { return UsedBytes; } + + uint32_t getClassSize() const { return SizeOf; } + + const PDBSymbol &getSymbol() const { return Symbol; } + + ArrayRef<std::unique_ptr<StorageItemBase>> layout_items() const { + return ChildStorage; + } + + ArrayRef<std::unique_ptr<PDBSymbol>> other_items() const { + return NonStorageItems; + } + +protected: + void initializeChildren(const PDBSymbol &Sym); + + void addChildToLayout(std::unique_ptr<StorageItemBase> Child); + + uint32_t SizeOf = 0; + std::string Name; + + const PDBSymbol &Symbol; + BitVector UsedBytes; + std::vector<std::unique_ptr<PDBSymbol>> NonStorageItems; + std::vector<std::unique_ptr<StorageItemBase>> ChildStorage; + std::vector<std::list<StorageItemBase *>> ChildrenPerByte; + std::vector<BaseClassLayout *> BaseClasses; + VTableLayoutItem *VTable = nullptr; +}; + +class ClassLayout : public UDTLayoutBase { +public: + explicit ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT); + +private: + std::unique_ptr<PDBSymbolTypeUDT> Type; +}; + +class BaseClassLayout : public UDTLayoutBase, public StorageItemBase { +public: + BaseClassLayout(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeBaseClass> Base); + +private: + std::unique_ptr<PDBSymbolTypeBaseClass> Base; + bool IsVirtualBase; +}; +} +} // namespace llvm + +#endif // LLVM_DEBUGINFO_PDB_UDTLAYOUT_H diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h index 3a0c5536c01..89d2af052dc 100644 --- a/llvm/include/llvm/Support/Casting.h +++ b/llvm/include/llvm/Support/Casting.h @@ -384,7 +384,7 @@ LLVM_NODISCARD inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) -> decltype(cast<X>(Val)) { if (!Val) return nullptr; - return unique_dyn_cast(Val); + return unique_dyn_cast<X, Y>(Val); } template <class X, class Y> diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt index 1295d2a19ce..f87a0b0a72e 100644 --- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt +++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt @@ -101,6 +101,7 @@ add_llvm_library(LLVMDebugInfoPDB PDBSymbolUnknown.cpp PDBSymbolUsingNamespace.cpp PDBSymDumper.cpp + UDTLayout.cpp ${PDB_IMPL_SOURCES} ADDITIONAL_HEADER_DIRS diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp index 6182dab213c..5e8c0bdc171 100644 --- a/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp +++ b/llvm/lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp @@ -14,6 +14,9 @@ #include "llvm/DebugInfo/PDB/DIA/DIAEnumSymbols.h" #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" @@ -717,6 +720,18 @@ uint32_t DIARawSymbol::getVirtualTableShapeId() const { return PrivateGetDIAValue(Symbol, &IDiaSymbol::get_virtualTableShapeId); } +std::unique_ptr<PDBSymbolTypeVTable> +DIARawSymbol::getVirtualBaseTableType() const { + CComPtr<IDiaSymbol> TableType; + if (FAILED(Symbol->get_virtualBaseTableType(&TableType)) || !TableType) + return nullptr; + + auto RawVT = llvm::make_unique<DIARawSymbol>(Session, TableType); + auto Pointer = + llvm::make_unique<PDBSymbolTypePointer>(Session, std::move(RawVT)); + return unique_dyn_cast<PDBSymbolTypeVTable>(Pointer->getPointeeType()); +} + PDB_DataKind DIARawSymbol::getDataKind() const { return PrivateGetDIAValue<DWORD, PDB_DataKind>(Symbol, &IDiaSymbol::get_dataKind); diff --git a/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp b/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp index 7077bda4a53..6ecf335812b 100644 --- a/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp +++ b/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -140,7 +140,7 @@ void DIASession::setLoadAddress(uint64_t Address) { Session->put_loadAddress(Address); } -std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() { +std::unique_ptr<PDBSymbolExe> DIASession::getGlobalScope() const { CComPtr<IDiaSymbol> GlobalScope; if (S_OK != Session->get_globalScope(&GlobalScope)) return nullptr; diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp index 4841ded7410..3aba35adb53 100644 --- a/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -13,6 +13,8 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" @@ -318,6 +320,11 @@ uint32_t NativeRawSymbol::getVirtualTableShapeId() const { return 0; } +std::unique_ptr<PDBSymbolTypeVTable> +NativeRawSymbol::getVirtualBaseTableType() const { + return nullptr; +} + PDB_DataKind NativeRawSymbol::getDataKind() const { return PDB_DataKind::Unknown; } diff --git a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp index 3a83a326cfe..7e6843bceb7 100644 --- a/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ b/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -70,8 +70,9 @@ uint64_t NativeSession::getLoadAddress() const { return 0; } void NativeSession::setLoadAddress(uint64_t Address) {} -std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() { - auto RawSymbol = llvm::make_unique<NativeExeSymbol>(*this); +std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() const { + auto RawSymbol = + llvm::make_unique<NativeExeSymbol>(const_cast<NativeSession &>(*this)); auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol))); std::unique_ptr<PDBSymbolExe> ExeSymbol( static_cast<PDBSymbolExe *>(PdbSymbol.release())); diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp index 2c8438f9c23..14eb6ba8ad8 100644 --- a/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp +++ b/llvm/lib/DebugInfo/PDB/PDBSymbol.cpp @@ -54,6 +54,9 @@ PDBSymbol::PDBSymbol(const IPDBSession &PDBSession, std::unique_ptr<IPDBRawSymbol> Symbol) : Session(PDBSession), RawSymbol(std::move(Symbol)) {} +PDBSymbol::PDBSymbol(PDBSymbol &Symbol) + : Session(Symbol.Session), RawSymbol(std::move(Symbol.RawSymbol)) {} + PDBSymbol::~PDBSymbol() = default; #define FACTORY_SYMTAG_CASE(Tag, Type) \ @@ -100,12 +103,6 @@ PDBSymbol::create(const IPDBSession &PDBSession, } } -#define TRY_DUMP_TYPE(Type) \ - if (const Type *DerivedThis = this->cast<Type>()) \ - Dumper.dump(OS, Indent, *DerivedThis); - -#define ELSE_TRY_DUMP_TYPE(Type, Dumper) else TRY_DUMP_TYPE(Type, Dumper) - void PDBSymbol::defaultDump(raw_ostream &OS, int Indent) const { RawSymbol->dump(OS, Indent); } diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolExe.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolExe.cpp index b9fcac78c36..7417167b61a 100644 --- a/llvm/lib/DebugInfo/PDB/PDBSymbolExe.cpp +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolExe.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include <utility> @@ -23,3 +24,13 @@ PDBSymbolExe::PDBSymbolExe(const IPDBSession &PDBSession, } void PDBSymbolExe::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); } + +uint32_t PDBSymbolExe::getPointerByteSize() const { + auto Pointer = findOneChild<PDBSymbolTypePointer>(); + if (Pointer) + return Pointer->getLength(); + + if (getMachineType() == PDB_Machine::x86) + return 4; + return 8; +} diff --git a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp index 4a9a9ed5fda..15dc1535216 100644 --- a/llvm/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp +++ b/llvm/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp @@ -9,7 +9,15 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" #include <utility> diff --git a/llvm/lib/DebugInfo/PDB/UDTLayout.cpp b/llvm/lib/DebugInfo/PDB/UDTLayout.cpp new file mode 100644 index 00000000000..71443fe7587 --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/UDTLayout.cpp @@ -0,0 +1,194 @@ +//===- UDTLayout.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/UDTLayout.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" + +#include <utility> + +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(); +} + +StorageItemBase::StorageItemBase(const UDTLayoutBase &Parent, + const PDBSymbol &Symbol, + const std::string &Name, + uint32_t OffsetInParent, uint32_t Size) + : Parent(Parent), Symbol(Symbol), Name(Name), SizeOf(Size), + OffsetInParent(OffsetInParent) { + UsedBytes.resize(SizeOf, true); +} + +uint32_t StorageItemBase::deepPaddingSize() const { + // sizeof(Field) - sizeof(typeof(Field)) is trailing padding. + return SizeOf - getTypeLength(Symbol); +} + +DataMemberLayoutItem::DataMemberLayoutItem( + const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> DataMember) + : StorageItemBase(Parent, *DataMember, DataMember->getName(), + DataMember->getOffset(), getTypeLength(*DataMember)), + DataMember(std::move(DataMember)) { + auto Type = this->DataMember->getType(); + if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) { + // UDT data members might have padding in between fields, but otherwise + // a member should occupy its entire storage. + UsedBytes.resize(SizeOf, false); + UdtLayout = llvm::make_unique<ClassLayout>(std::move(UDT)); + } +} + +const PDBSymbolData &DataMemberLayoutItem::getDataMember() { + return *dyn_cast<PDBSymbolData>(&Symbol); +} + +uint32_t DataMemberLayoutItem::deepPaddingSize() const { + uint32_t Result = StorageItemBase::deepPaddingSize(); + if (UdtLayout) + Result += UdtLayout->deepPaddingSize(); + return Result; +} + +VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeVTable> VTable) + : StorageItemBase(Parent, *VTable, "<vtbl>", 0, getTypeLength(*VTable)), + VTable(std::move(VTable)) { + // initialize vtbl methods. + auto VTableType = cast<PDBSymbolTypePointer>(this->VTable->getType()); + uint32_t PointerSize = VTableType->getLength(); + + if (auto Shape = unique_dyn_cast<PDBSymbolTypeVTableShape>( + VTableType->getPointeeType())) { + VTableFuncs.resize(Shape->getCount()); + + auto ParentFunctions = Parent.getSymbol().findAllChildren<PDBSymbolFunc>(); + while (auto Func = ParentFunctions->getNext()) { + if (Func->isVirtual()) { + uint32_t Index = Func->getVirtualBaseOffset(); + assert(Index % PointerSize == 0); + Index /= PointerSize; + + // Don't allow a compiler generated function to overwrite a user + // function in the VTable. Not sure why this happens, but a function + // named __vecDelDtor sometimes shows up on top of the destructor. + if (Func->isCompilerGenerated() && VTableFuncs[Index]) + continue; + VTableFuncs[Index] = std::move(Func); + } + } + } +} + +UDTLayoutBase::UDTLayoutBase(const PDBSymbol &Symbol, const std::string &Name, + uint32_t Size) + : Symbol(Symbol), Name(Name), SizeOf(Size) { + UsedBytes.resize(Size); + ChildrenPerByte.resize(Size); + initializeChildren(Symbol); +} + +ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT) + : UDTLayoutBase(*UDT, UDT->getName(), UDT->getLength()), + Type(std::move(UDT)) {} + +BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent, + std::unique_ptr<PDBSymbolTypeBaseClass> Base) + : UDTLayoutBase(*Base, Base->getName(), Base->getLength()), + StorageItemBase(Parent, *Base, Base->getName(), Base->getOffset(), + Base->getLength()), + Base(std::move(Base)) { + IsVirtualBase = this->Base->isVirtualBaseClass(); +} + +uint32_t UDTLayoutBase::shallowPaddingSize() const { + return UsedBytes.size() - UsedBytes.count(); +} + +uint32_t UDTLayoutBase::deepPaddingSize() const { + uint32_t Result = shallowPaddingSize(); + for (auto &Child : ChildStorage) + Result += Child->deepPaddingSize(); + return Result; +} + +void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) { + auto Children = Sym.findAllChildren(); + while (auto Child = Children->getNext()) { + if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) { + if (Data->getDataKind() == PDB_DataKind::Member) { + auto DM = + llvm::make_unique<DataMemberLayoutItem>(*this, std::move(Data)); + + addChildToLayout(std::move(DM)); + } else { + NonStorageItems.push_back(std::move(Data)); + } + continue; + } + + if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) { + auto BL = llvm::make_unique<BaseClassLayout>(*this, std::move(Base)); + BaseClasses.push_back(BL.get()); + + addChildToLayout(std::move(BL)); + continue; + } + + if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child)) { + auto VTLayout = llvm::make_unique<VTableLayoutItem>(*this, std::move(VT)); + + VTable = VTLayout.get(); + + addChildToLayout(std::move(VTLayout)); + continue; + } + + NonStorageItems.push_back(std::move(Child)); + } +} + +void UDTLayoutBase::addChildToLayout(std::unique_ptr<StorageItemBase> Child) { + uint32_t Begin = Child->getOffsetInParent(); + uint32_t End = Begin + Child->getSize(); + UsedBytes.set(Begin, End); + while (Begin != End) { + ChildrenPerByte[Begin].push_back(Child.get()); + ++Begin; + } + + auto Loc = std::upper_bound( + ChildStorage.begin(), ChildStorage.end(), Begin, + [](uint32_t Off, const std::unique_ptr<StorageItemBase> &Item) { + return Off < Item->getOffsetInParent(); + }); + + ChildStorage.insert(Loc, std::move(Child)); +}
\ No newline at end of file diff --git a/llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test b/llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test index 60a19534687..0bb3e001d3a 100644 --- a/llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test +++ b/llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test @@ -32,14 +32,14 @@ ; TYPES_FORMAT-DAG: typedef class A ClassAType ; TYPES_1: Classes -; TYPES_1: struct A { +; TYPES_1: struct A [sizeof = 4] { ; TYPES_1: virtual void PureFunc() = 0 ; TYPES_1: virtual void VirtualFunc() ; TYPES_1: void RegularFunc() ; TYPES_1: } ; TYPES_2: Classes -; TYPES_2: struct MemberTest { +; TYPES_2: struct MemberTest [sizeof = 96] { ; TYPES_2: data +0x00 [sizeof=4] MemberTest::NestedEnum m_nested_enum ; TYPES_2: data +0x04 [sizeof=4] int m_typedef ; TYPES_2: data +0x08 [sizeof=1] bool m_bool diff --git a/llvm/test/DebugInfo/PDB/Inputs/symbolformat.pdb b/llvm/test/DebugInfo/PDB/Inputs/symbolformat.pdb Binary files differindex 0e509f3a93c..9272f318258 100644 --- a/llvm/test/DebugInfo/PDB/Inputs/symbolformat.pdb +++ b/llvm/test/DebugInfo/PDB/Inputs/symbolformat.pdb diff --git a/llvm/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp b/llvm/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp new file mode 100644 index 00000000000..b10839beea2 --- /dev/null +++ b/llvm/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp @@ -0,0 +1,122 @@ +// Compile with "cl /c /Zi /GR- SimplePaddingTest.cpp" +// Link with "link SimplePaddingTest.obj /debug /nodefaultlib /entry:main" + +#include <stdint.h> + +extern "C" using at_exit_handler = void(); + +int atexit(at_exit_handler handler) { return 0; } + +struct SimplePadNoPadding { + int32_t X; + int32_t Y; + // No padding anywhere, sizeof(T) = 8 +} A; + +struct SimplePadUnion { + union { + int32_t X; + int64_t Y; + struct { + int32_t X; + // 4 bytes of padding here + int64_t Y; + } Z; + }; + // Since the padding occurs at a location that is occupied by other storage + // (namely the Y member), the storage will still be considered used, and so + // there will be no unused bytes in the larger class. But in the debug + // info for the nested struct, we should see padding. + // sizeof(SimplePadUnion) == sizeof(Z) == 16 +} B; + +struct SimplePadNoPadding2 { + bool A; + bool B; + bool C; + bool D; + // No padding anywhere, sizeof(T) = 4 +} C; + +struct alignas(4) SimplePadFields1 { + char A; + char B; + char C; + // 1 byte of padding here, sizeof(T) = 4 +} E; + +struct SimplePadFields2 { + int32_t Y; + char X; +} F; + +struct SimplePadBase { + // Make sure this class is 4 bytes, and the derived class requires 8 byte + // alignment, so that padding is inserted between base and derived. + int32_t X; + // No padding here +} G; + +struct SimplePadDerived : public SimplePadBase { + // 4 bytes of padding here due to Y requiring 8 byte alignment. + // Thus, sizeof(T) = 16 + int64_t Y; +} H; + +struct SimplePadEmptyBase1 {}; +struct SimplePadEmptyBase2 {}; + +struct SimplePadEmpty : public SimplePadEmptyBase1, SimplePadEmptyBase2 { + // Bases have to occupy at least 1 byte of storage, so this requires + // 2 bytes of padding, plus 1 byte for each base, yielding sizeof(T) = 8 + int32_t X; +} I; + +struct SimplePadVfptr { + virtual ~SimplePadVfptr() {} + static void operator delete(void *ptr, size_t sz) {} + int32_t X; +} J; + +struct NonEmptyBase1 { + bool X; +}; + +struct NonEmptyBase2 { + bool Y; +}; + +struct SimplePadMultiInherit : public NonEmptyBase1, public NonEmptyBase2 { + // X and Y from the 2 bases will get squished together, leaving 2 bytes + // of padding necessary for proper alignment of an int32. + // Therefore, sizeof(T) = 2 + 2 + 4 = 8 + int32_t X; +} K; + +struct SimplePadMultiInherit2 : public SimplePadFields1, SimplePadFields2 { + // There should be 1 byte of padding after the first class, and + // 3 bytes of padding after the second class. + int32_t X; +} L; + +struct OneLevelInherit : public NonEmptyBase1 { + short Y; +}; + +struct SimplePadTwoLevelInherit : public OneLevelInherit { + // OneLevelInherit has nested padding because of its base, + // and then padding again because of this class. So each + // class should be 4 bytes, yielding sizeof(T) = 12. + int64_t Z; +} M; + +struct SimplePadAggregate { + NonEmptyBase1 X; + int32_t Y; + // the presence of X will cause 3 bytes of padding to be injected. +} N; + +int main(int argc, char **argv) { + + return 0; +} diff --git a/llvm/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb b/llvm/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb Binary files differnew file mode 100644 index 00000000000..44207d60193 --- /dev/null +++ b/llvm/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb diff --git a/llvm/test/tools/llvm-pdbdump/class-layout.test b/llvm/test/tools/llvm-pdbdump/class-layout.test index e2921d298fc..c0083d176ea 100644 --- a/llvm/test/tools/llvm-pdbdump/class-layout.test +++ b/llvm/test/tools/llvm-pdbdump/class-layout.test @@ -14,38 +14,39 @@ ; GLOBALS_TEST-DAG: GlobalsTest::Enum GlobalsTest::EnumVar ; MEMBERS_TEST: ---TYPES--- -; MEMBERS_TEST: class MembersTest::A { +; MEMBERS_TEST: class MembersTest::A [sizeof = 16] { ; MEMBERS_TEST-DAG: typedef int NestedTypedef ; MEMBERS_TEST-DAG: enum NestedEnum ; MEMBERS_TEST: void MemberFunc() -; MEMBERS_TEST-DAG: int IntMemberVar -; MEMBERS_TEST-DAG: double DoubleMemberVar +; MEMBERS_TEST-DAG: data +0x00 [sizeof=4] int IntMemberVar +; MEMBERS_TEST-NEXT: <padding> (4 bytes) +; MEMBERS_TEST-NEXT: data +0x08 [sizeof=8] double DoubleMemberVar ; MEMBERS_TEST: } ; BASE_CLASS_A: ---TYPES--- -; BASE_CLASS_A: class BaseClassTest::A {} +; BASE_CLASS_A: class BaseClassTest::A [sizeof = 1] {} ; BASE_CLASS_B: ---TYPES--- -; BASE_CLASS_B: class BaseClassTest::B +; BASE_CLASS_B: class BaseClassTest::B [sizeof = 4] ; BASE_CLASS_B-NEXT: : public virtual BaseClassTest::A { ; BASE_CLASS_C: ---TYPES--- -; BASE_CLASS_C: class BaseClassTest::C +; BASE_CLASS_C: class BaseClassTest::C [sizeof = 4] ; BASE_CLASS_C-NEXT: : public virtual BaseClassTest::A { ; BASE_CLASS_D: ---TYPES--- -; BASE_CLASS_D: class BaseClassTest::D +; BASE_CLASS_D: class BaseClassTest::D [sizeof = 8] ; BASE_CLASS_D-DAG: protected BaseClassTest::B ; BASE_CLASS_D-DAG: private BaseClassTest::C ; BASE_CLASS_D-DAG: protected virtual BaseClassTest::A ; UDT_KIND_TEST: ---TYPES--- -; UDT_KIND_TEST-DAG: union UdtKindTest::C {} -; UDT_KIND_TEST-DAG: class UdtKindTest::B {} -; UDT_KIND_TEST-DAG: struct UdtKindTest::A {} +; UDT_KIND_TEST-DAG: union UdtKindTest::C [sizeof = 1] {} +; UDT_KIND_TEST-DAG: class UdtKindTest::B [sizeof = 1] {} +; UDT_KIND_TEST-DAG: struct UdtKindTest::A [sizeof = 1] {} ; BITFIELD_TEST: ---TYPES--- -; BITFIELD_TEST: struct BitFieldTest::A { +; BITFIELD_TEST: struct BitFieldTest::A [sizeof = 8] { ; BITFIELD_TEST-NEXT: +0x00 [sizeof=4] int Bits1 : 1 ; BITFIELD_TEST-NEXT: +0x00 [sizeof=4] int Bits2 : 2 ; BITFIELD_TEST-NEXT: +0x00 [sizeof=4] int Bits3 : 3 diff --git a/llvm/test/tools/llvm-pdbdump/enum-layout.test b/llvm/test/tools/llvm-pdbdump/enum-layout.test index 21e1867175f..df447c65bba 100644 --- a/llvm/test/tools/llvm-pdbdump/enum-layout.test +++ b/llvm/test/tools/llvm-pdbdump/enum-layout.test @@ -10,7 +10,7 @@ ; MEMBER_ENUM: ---TYPES--- ; MEMBER_ENUM: Classes: -; MEMBER_ENUM: struct __vc_attributes::threadingAttribute { +; MEMBER_ENUM: struct __vc_attributes::threadingAttribute [sizeof = 4] { ; MEMBER_ENUM-NEXT: enum threading_e { ; MEMBER_ENUM-NEXT: apartment = 1 ; MEMBER_ENUM-NEXT: single = 2 diff --git a/llvm/test/tools/llvm-pdbdump/simple-padding.test b/llvm/test/tools/llvm-pdbdump/simple-padding.test new file mode 100644 index 00000000000..4096d287a56 --- /dev/null +++ b/llvm/test/tools/llvm-pdbdump/simple-padding.test @@ -0,0 +1,94 @@ +; RUN: llvm-pdbdump pretty -classes -class-definitions=layout \ +; RUN: -include-types=SimplePad %p/Inputs/SimplePaddingTest.pdb > %t + +; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PADDING +; RUN: FileCheck -input-file=%t %s -check-prefix=UNION +; RUN: FileCheck -input-file=%t %s -check-prefix=NESTED_UNION +; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS1 +; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_FROM_FIELDS2 +; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PAD_IN_BASE +; RUN: FileCheck -input-file=%t %s -check-prefix=PAD_IN_DERIVED +; RUN: FileCheck -input-file=%t %s -check-prefix=EMPTY_BASE +; RUN: FileCheck -input-file=%t %s -check-prefix=VFPTR +; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT +; RUN: FileCheck -input-file=%t %s -check-prefix=MULTIPLE_INHERIT2 +; RUN: FileCheck -input-file=%t %s -check-prefix=DEEP_INHERIT +; RUN: FileCheck -input-file=%t %s -check-prefix=AGGREGATE + +; NO_PADDING: struct SimplePadNoPadding [sizeof = 8] { +; NO_PADDING-NEXT: data +0x00 [sizeof=4] int X +; NO_PADDING-NEXT: data +0x04 [sizeof=4] int Y +; NO_PADDING-NEXT: } + +; UNION: struct SimplePadUnion [sizeof = 16] { +; UNION-NEXT: data +0x00 [sizeof=4] int X +; UNION-NEXT: data +0x00 [sizeof=8] __int64 Y +; UNION-NEXT: data +0x00 [sizeof=16] SimplePadUnion:: +; UNION-NEXT: } + +; NESTED_UNION: struct {{SimplePadUnion::.*}} [sizeof = 16] { +; NESTED_UNION-NEXT: data +0x00 [sizeof=4] int X +; NESTED_UNION-NEXT: <padding> (4 bytes) +; NESTED_UNION-NEXT: data +0x08 [sizeof=8] __int64 Y +; NESTED_UNION-NEXT: } + +; PAD_FROM_FIELDS1: struct SimplePadFields1 [sizeof = 4] { +; PAD_FROM_FIELDS1-NEXT: data +0x00 [sizeof=1] char A +; PAD_FROM_FIELDS1-NEXT: data +0x01 [sizeof=1] char B +; PAD_FROM_FIELDS1-NEXT: data +0x02 [sizeof=1] char C +; PAD_FROM_FIELDS1-NEXT: <padding> (1 bytes) +; PAD_FROM_FIELDS1-NEXT: } + +; PAD_FROM_FIELDS2: struct SimplePadFields2 [sizeof = 8] { +; PAD_FROM_FIELDS2-NEXT: data +0x00 [sizeof=4] int Y +; PAD_FROM_FIELDS2-NEXT: data +0x04 [sizeof=1] char X +; PAD_FROM_FIELDS2-NEXT: <padding> (3 bytes) +; PAD_FROM_FIELDS2-NEXT: } + +; NO_PAD_IN_BASE: struct SimplePadBase [sizeof = 4] { +; NO_PAD_IN_BASE-NEXT: data +0x00 [sizeof=4] int X +; NO_PAD_IN_BASE-NEXT: } + +; PAD_IN_DERIVED: struct SimplePadDerived [sizeof = 16] +; PAD_IN_DERIVED-NEXT: public SimplePadBase { +; PAD_IN_DERIVED-NEXT: <padding> (4 bytes) +; PAD_IN_DERIVED-NEXT: data +0x08 [sizeof=8] __int64 Y +; PAD_IN_DERIVED-NEXT: } + +; EMPTY_BASE: struct SimplePadEmpty [sizeof = 8] +; EMPTY_BASE-NEXT: : public SimplePadEmptyBase1 +; EMPTY_BASE-NEXT: , public SimplePadEmptyBase2 { +; EMPTY_BASE-NEXT: <padding> (2 bytes) +; EMPTY_BASE-NEXT: data +0x04 [sizeof=4] int X +; EMPTY_BASE-NEXT: } + +; VFPTR: struct SimplePadVfptr [sizeof = 8] { +; VFPTR-NEXT: data +0x00 [sizeof=4] __vfptr +; VFPTR-NEXT: data +0x04 [sizeof=4] int X +; VFPTR-NEXT: } + +; MULTIPLE_INHERIT: struct SimplePadMultiInherit [sizeof = 8] +; MULTIPLE_INHERIT-NEXT: : public NonEmptyBase1 +; MULTIPLE_INHERIT-NEXT: , public NonEmptyBase2 { +; MULTIPLE_INHERIT-NEXT: <padding> (2 bytes) +; MULTIPLE_INHERIT-NEXT: data +0x04 [sizeof=4] int X +; MULTIPLE_INHERIT-NEXT: } + +; MULTIPLE_INHERIT2: SimplePadMultiInherit2 [sizeof = 16] +; MULTIPLE_INHERIT2-NEXT: : public SimplePadFields1 +; MULTIPLE_INHERIT2-NEXT: , public SimplePadFields2 { +; MULTIPLE_INHERIT2-NEXT: data +0x0c [sizeof=4] int X +; MULTIPLE_INHERIT2-NEXT: } + +; DEEP_INHERIT: struct SimplePadTwoLevelInherit [sizeof = 16] +; DEEP_INHERIT-NEXT: : public OneLevelInherit { +; DEEP_INHERIT-NEXT: <padding> (4 bytes) +; DEEP_INHERIT-NEXT: data +0x08 [sizeof=8] __int64 Z +; DEEP_INHERIT-NEXT: } + + +; AGGREGATE: struct SimplePadAggregate [sizeof = 8] { +; AGGREGATE-NEXT: data +0x00 [sizeof=1] NonEmptyBase1 X +; AGGREGATE-NEXT: <padding> (3 bytes) +; AGGREGATE-NEXT: data +0x04 [sizeof=4] int Y +; AGGREGATE-NEXT: } diff --git a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp index b48ed23c1c7..2e1e54e4db1 100644 --- a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp +++ b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp @@ -28,7 +28,8 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" -#include "llvm/Support/Compiler.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" + #include "llvm/Support/Format.h" using namespace llvm; @@ -37,58 +38,23 @@ using namespace llvm::pdb; ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} -static void analyzePadding(const PDBSymbolTypeUDT &Class, BitVector &Padding, - uint32_t &FirstFieldOffset) { - Padding.resize(Class.getLength(), true); - auto Children = Class.findAllChildren<PDBSymbolData>(); - bool IsFirst = true; - FirstFieldOffset = Class.getLength(); - - while (auto Data = Children->getNext()) { - // Ignore data members which are not relative to this. Usually these are - // static data members or constexpr and occupy no space. We also need to - // handle BitFields since the PDB doesn't consider them ThisRel, but they - // still occupy space in the record layout. - auto LocType = Data->getLocationType(); - if (LocType != PDB_LocType::ThisRel && LocType != PDB_LocType::BitField) - continue; - - uint64_t Start = Data->getOffset(); - if (IsFirst) { - FirstFieldOffset = Start; - IsFirst = false; - } - - auto VarType = Data->getType(); - uint64_t Size = VarType->getRawSymbol().getLength(); - Padding.reset(Start, Start + Size); - } - - // Unmark anything that comes before the first field so it doesn't get - // counted as padding. In reality this is going to be vptrs or base class - // members, but we don't correctly handle that yet. - // FIXME: Handle it. - Padding.reset(0, FirstFieldOffset); -} - void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { assert(opts::pretty::ClassFormat != opts::pretty::ClassDefinitionFormat::None); uint32_t Size = Class.getLength(); - uint32_t FirstFieldOffset = 0; - BitVector Padding; - analyzePadding(Class, Padding, FirstFieldOffset); - if (opts::pretty::OnlyPaddingClasses && (Padding.count() == 0)) + ClassLayout Layout(Class.clone()); + + if (opts::pretty::OnlyPaddingClasses && (Layout.shallowPaddingSize() == 0)) return; Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Comment).get() << "// sizeof = " << Size; - Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); + WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size + << "]"; auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>(); if (Bases->getChildCount() > 0) { @@ -111,60 +77,54 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { } Printer << " {"; - auto Children = Class.findAllChildren(); Printer.Indent(); - int DumpedCount = 0; - - int NextPaddingByte = Padding.find_first(); - while (auto Child = Children->getNext()) { - if (auto Data = llvm::dyn_cast<PDBSymbolData>(Child.get())) { - if (Data->getDataKind() == PDB_DataKind::Member && NextPaddingByte >= 0) { - // If there are padding bytes remaining, see if this field is the first - // to cross a padding boundary, and print a padding field indicator if - // so. - int Off = Data->getOffset(); - if (Off > NextPaddingByte) { - uint32_t Amount = Off - NextPaddingByte; - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Padding).get() - << "<padding> (" << Amount << " bytes)"; - assert(Padding.find_next_unset(NextPaddingByte) == Off); - NextPaddingByte = Padding.find_next(Off); - } - } - } - if (auto Func = Child->cast<PDBSymbolFunc>()) { - if (Func->isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) - continue; + // Dump non-layout items first, but only if we're not in layout-only mode. + if (opts::pretty::ClassFormat != + opts::pretty::ClassDefinitionFormat::Layout) { + for (auto &Other : Layout.other_items()) + Other->dump(*this); + } - if (Func->getLength() == 0 && !Func->isPureVirtual() && - !Func->isIntroVirtualFunction()) - continue; + const BitVector &UseMap = Layout.usedBytes(); + int NextUnusedByte = Layout.usedBytes().find_first_unset(); + // Next dump items which affect class layout. + for (auto &LayoutItem : Layout.layout_items()) { + if (NextUnusedByte >= 0) { + // If there are padding bytes remaining, see if this field is the first to + // cross a padding boundary, and print a padding field indicator if so. + int Off = LayoutItem->getOffsetInParent(); + if (Off > NextUnusedByte) { + uint32_t Amount = Off - NextUnusedByte; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" + << Amount << " bytes)"; + assert(UseMap.find_next(NextUnusedByte) == Off); + NextUnusedByte = UseMap.find_next_unset(Off); + } } - - ++DumpedCount; - Child->dump(*this); + LayoutItem->getSymbol().dump(*this); } - if (NextPaddingByte >= 0) { - uint32_t Amount = Size - NextPaddingByte; + if (NextUnusedByte >= 0 && Layout.getClassSize() > 1) { + uint32_t Amount = Layout.getClassSize() - NextUnusedByte; Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Padding).get() << "<padding> (" << Amount << " bytes)"; + DumpedAnything = true; } + Printer.Unindent(); - if (DumpedCount > 0) + if (DumpedAnything) Printer.NewLine(); Printer << "}"; Printer.NewLine(); - if (Padding.count() > 0) { - APFloat Pct(100.0 * (double)Padding.count() / - (double)(Size - FirstFieldOffset)); + if (Layout.deepPaddingSize() > 0) { + APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / (double)Size); SmallString<8> PctStr; Pct.toString(PctStr, 4); WithColor(Printer, PDB_ColorItem::Padding).get() - << "Total padding " << Padding.count() << " bytes (" << PctStr + << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr << "% of class size)"; Printer.NewLine(); } @@ -175,23 +135,35 @@ void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {} void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) { VariableDumper Dumper(Printer); Dumper.start(Symbol); + DumpedAnything = true; } void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) { if (Printer.IsSymbolExcluded(Symbol.getName())) return; + if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) + return; + if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() && + !Symbol.isIntroVirtualFunction()) + return; + DumpedAnything = true; Printer.NewLine(); FunctionDumper Dumper(Printer); Dumper.start(Symbol, FunctionDumper::PointerType::None); } -void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {} +void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) { + VariableDumper Dumper(Printer); + Dumper.start(Symbol); + DumpedAnything = true; +} void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) { if (Printer.IsTypeExcluded(Symbol.getName())) return; + DumpedAnything = true; Printer.NewLine(); EnumDumper Dumper(Printer); Dumper.start(Symbol); @@ -201,6 +173,7 @@ void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) { if (Printer.IsTypeExcluded(Symbol.getName())) return; + DumpedAnything = true; Printer.NewLine(); TypedefDumper Dumper(Printer); Dumper.start(Symbol); diff --git a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h index 8f0c35cba81..94ae07d345d 100644 --- a/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h +++ b/llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h @@ -21,6 +21,8 @@ #include <unordered_map> namespace llvm { +class BitVector; + namespace pdb { class LinePrinter; @@ -40,6 +42,10 @@ public: void dump(const PDBSymbolTypeVTable &Symbol) override; private: + bool maybeDumpSymbol(std::unique_ptr<PDBSymbolData> Data, + const BitVector &Padding, int &NextUnusedByte); + bool maybeDumpSymbol(std::unique_ptr<PDBSymbolFunc> Data); + bool DumpedAnything = false; LinePrinter &Printer; }; } diff --git a/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp index 0e0da026e56..b0be33c157c 100644 --- a/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp +++ b/llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp @@ -233,7 +233,7 @@ void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) { if (!PointeeType) return; - if (auto FuncSig = PointeeType->cast<PDBSymbolTypeFunctionSig>()) { + if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) { FunctionDumper NestedDumper(Printer); PointerType Pointer = Symbol.isReference() ? PointerType::Reference : PointerType::Pointer; diff --git a/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp index 12a47d24f79..2857b07078c 100644 --- a/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp +++ b/llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp @@ -26,6 +26,23 @@ using namespace llvm; using namespace llvm::pdb; +template <typename Enumerator> +static std::vector<std::unique_ptr<PDBSymbolTypeUDT>> +filterClassDefs(LinePrinter &Printer, Enumerator &E) { + std::vector<std::unique_ptr<PDBSymbolTypeUDT>> Filtered; + while (auto Class = E.getNext()) { + if (Class->getUnmodifiedTypeId() != 0) + continue; + + if (Printer.IsTypeExcluded(Class->getName())) + continue; + + Filtered.push_back(std::move(Class)); + } + + return Filtered; +} + TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} void TypeDumper::start(const PDBSymbolExe &Exe) { @@ -53,11 +70,19 @@ void TypeDumper::start(const PDBSymbolExe &Exe) { if (opts::pretty::Classes) { auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>(); + auto Filtered = filterClassDefs(Printer, *Classes); + Printer.NewLine(); + uint32_t Shown = Filtered.size(); + uint32_t All = Classes->getChildCount(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; - Printer << ": (" << Classes->getChildCount() << " items)"; + Printer << ": (Showing " << Shown << " items"; + if (Shown < All) + Printer << ", " << (All - Shown) << " filtered"; + Printer << ")"; Printer.Indent(); - while (auto Class = Classes->getNext()) + for (auto &Class : Filtered) Class->dump(*this); Printer.Unindent(); } @@ -91,11 +116,6 @@ void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) { assert(opts::pretty::Classes); - if (Symbol.getUnmodifiedTypeId() != 0) - return; - if (Printer.IsTypeExcluded(Symbol.getName())) - return; - if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { Printer.NewLine(); WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; diff --git a/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp index 861f7e28b38..2d8e915d760 100644 --- a/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp +++ b/llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp @@ -54,7 +54,7 @@ void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) { if (Symbol.isVolatileType()) WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; auto PointeeType = Symbol.getPointeeType(); - if (auto FuncSig = PointeeType->cast<PDBSymbolTypeFunctionSig>()) { + if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) { FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer; if (Symbol.isReference()) Pointer = FunctionDumper::PointerType::Reference; diff --git a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp index 65f0139dfbc..ef9a9b51bd0 100644 --- a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp +++ b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp @@ -91,6 +91,19 @@ void VariableDumper::start(const PDBSymbolData &Var) { } } +void VariableDumper::start(const PDBSymbolTypeVTable &Var) { + Printer.NewLine(); + Printer << "data "; + auto VTableType = cast<PDBSymbolTypePointer>(Var.getType()); + uint32_t PointerSize = VTableType->getLength(); + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Var.getOffset(), 4) << " [sizeof=" << PointerSize + << "] "; + + WithColor(Printer, PDB_ColorItem::Identifier).get() << " __vfptr"; +} + void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) { auto ElementType = Symbol.getElementType(); assert(ElementType); @@ -157,12 +170,12 @@ void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) { if (!PointeeType) return; PointeeType->dump(*this); - if (auto Func = PointeeType->cast<PDBSymbolTypeFunctionSig>()) { + if (auto FuncSig = unique_dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType)) { // A hack to get the calling convention in the right spot. Printer << " ("; - PDB_CallingConv CC = Func->getCallingConvention(); + PDB_CallingConv CC = FuncSig->getCallingConvention(); WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; - } else if (isa<PDBSymbolTypeArray>(PointeeType.get())) { + } else if (isa<PDBSymbolTypeArray>(PointeeType)) { Printer << " ("; } Printer << (Symbol.isReference() ? "&" : "*"); @@ -177,8 +190,8 @@ void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) { assert(PointeeType); if (!PointeeType) return; - if (isa<PDBSymbolTypeFunctionSig>(PointeeType.get()) || - isa<PDBSymbolTypeArray>(PointeeType.get())) { + if (isa<PDBSymbolTypeFunctionSig>(PointeeType) || + isa<PDBSymbolTypeArray>(PointeeType)) { Printer << ")"; } PointeeType->dumpRight(*this); diff --git a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h index eec389b1707..ba9fdb17655 100644 --- a/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h +++ b/llvm/tools/llvm-pdbdump/PrettyVariableDumper.h @@ -25,6 +25,7 @@ public: VariableDumper(LinePrinter &P); void start(const PDBSymbolData &Var); + void start(const PDBSymbolTypeVTable &Var); void dump(const PDBSymbolTypeArray &Symbol) override; void dump(const PDBSymbolTypeBuiltin &Symbol) override; diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp index 8a749bab98e..a486c8a0730 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -96,7 +96,7 @@ cl::SubCommand "Analyze various aspects of a PDB's structure"); cl::OptionCategory TypeCategory("Symbol Type Options"); -cl::OptionCategory FilterCategory("Filtering Options"); +cl::OptionCategory FilterCategory("Filtering and Sorting Options"); cl::OptionCategory OtherOptions("Other Options"); namespace pretty { @@ -122,14 +122,17 @@ cl::opt<bool> Enums("enums", cl::desc("Display enum types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt<bool> Typedefs("typedefs", cl::desc("Display typedef types"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt<ClassDefinitionFormat> - ClassFormat("class-definitions", cl::desc("Class definition format"), - cl::init(ClassDefinitionFormat::Standard), - cl::values(clEnumValN(ClassDefinitionFormat::Standard, "full", - "Display complete class definition"), - clEnumValN(ClassDefinitionFormat::None, "none", - "Don't display class definitions")), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt<ClassDefinitionFormat> ClassFormat( + "class-definitions", cl::desc("Class definition format"), + cl::init(ClassDefinitionFormat::Standard), + cl::values( + clEnumValN(ClassDefinitionFormat::Standard, "full", + "Display complete class definition"), + clEnumValN(ClassDefinitionFormat::Layout, "layout", + "Only display members that contribute to class size."), + clEnumValN(ClassDefinitionFormat::None, "none", + "Don't display class definitions")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); cl::opt<bool> Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); diff --git a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h index a335d30c4cf..c572176f76d 100644 --- a/llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/llvm/tools/llvm-pdbdump/llvm-pdbdump.h @@ -18,7 +18,7 @@ namespace opts { namespace pretty { -enum class ClassDefinitionFormat { None, Standard }; +enum class ClassDefinitionFormat { None, Layout, Standard }; extern llvm::cl::opt<bool> Compilands; extern llvm::cl::opt<bool> Symbols; diff --git a/llvm/unittests/DebugInfo/PDB/PDBApiTest.cpp b/llvm/unittests/DebugInfo/PDB/PDBApiTest.cpp index ba09a8e2842..6afe83cd90d 100644 --- a/llvm/unittests/DebugInfo/PDB/PDBApiTest.cpp +++ b/llvm/unittests/DebugInfo/PDB/PDBApiTest.cpp @@ -63,7 +63,7 @@ namespace { class MockSession : public IPDBSession { uint64_t getLoadAddress() const override { return 0; } void setLoadAddress(uint64_t Address) override {} - std::unique_ptr<PDBSymbolExe> getGlobalScope() override { + std::unique_ptr<PDBSymbolExe> getGlobalScope() const override { return nullptr; } std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override { @@ -226,6 +226,7 @@ public: MOCK_SYMBOL_ACCESSOR(getMachineType) MOCK_SYMBOL_ACCESSOR(getThunkOrdinal) MOCK_SYMBOL_ACCESSOR(getLength) + MOCK_SYMBOL_ACCESSOR(getVirtualBaseTableType) MOCK_SYMBOL_ACCESSOR(getLiveRangeLength) MOCK_SYMBOL_ACCESSOR(getVirtualAddress) MOCK_SYMBOL_ACCESSOR(getUdtKind) |

