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;
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>
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
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;
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>
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;
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>
protected:
PDBSymbol(const IPDBSession &PDBSession,
std::unique_ptr<IPDBRawSymbol> Symbol);
+ PDBSymbol(PDBSymbol &Symbol);
public:
static std::unique_ptr<PDBSymbol>
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>
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
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;
#include "PDBSymbol.h"
#include "PDBTypes.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
+
namespace llvm {
class raw_ostream;
#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 {
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;
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)
--- /dev/null
+//===- 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
-> 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>
PDBSymbolUnknown.cpp
PDBSymbolUsingNamespace.cpp
PDBSymDumper.cpp
+ UDTLayout.cpp
${PDB_IMPL_SOURCES}
ADDITIONAL_HEADER_DIRS
#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"
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);
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;
#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"
return 0;
}
+std::unique_ptr<PDBSymbolTypeVTable>
+NativeRawSymbol::getVirtualBaseTableType() const {
+ return nullptr;
+}
+
PDB_DataKind NativeRawSymbol::getDataKind() const {
return PDB_DataKind::Unknown;
}
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()));
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) \
}
}
-#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);
}
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
#include <utility>
}
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;
+}
#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>
--- /dev/null
+//===- 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
; 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
--- /dev/null
+// 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;
+}
; 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
; 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
--- /dev/null
+; 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: }
#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;
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) {
}
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();
}
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);
if (Printer.IsTypeExcluded(Symbol.getName()))
return;
+ DumpedAnything = true;
Printer.NewLine();
TypedefDumper Dumper(Printer);
Dumper.start(Symbol);
#include <unordered_map>
namespace llvm {
+class BitVector;
+
namespace pdb {
class LinePrinter;
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;
};
}
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;
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) {
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();
}
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 ";
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;
}
}
+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);
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() ? "&" : "*");
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);
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;
"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 {
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));
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;
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 {
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)