]> granicus.if.org Git - llvm/commitdiff
[llvm-pdbdump] More advanced class definition dumping.
authorZachary Turner <zturner@google.com>
Wed, 12 Apr 2017 23:18:21 +0000 (23:18 +0000)
committerZachary Turner <zturner@google.com>
Wed, 12 Apr 2017 23:18:21 +0000 (23:18 +0000)
Previously the dumping of class definitions was very primitive,
and it made it hard to do more than the most trivial of output
formats when dumping.  As such, we would only dump one line for
each field, and then dump non-layout items like nested types
and enums.

With this patch, we do a complete analysis of the object
hierarchy including aggregate types, bases, virtual bases,
vftable analysis, etc.  The only immediately visible effects
of this are that a) we can now dump a line for the vfptr where
before we would treat that as padding, and b) we now don't
treat virtual bases that come at the end of a class as padding
since we have a more detailed analysis of the class's storage
usage.

In subsequent patches, we should be able to use this analysis
to display a complete graphical view of a class's layout including
recursing arbitrarily deep into an object's base class / aggregate
member hierarchy.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300133 91177308-0d34-0410-b5e6-96231b3b80d8

39 files changed:
include/llvm/DebugInfo/PDB/DIA/DIARawSymbol.h
include/llvm/DebugInfo/PDB/DIA/DIASession.h
include/llvm/DebugInfo/PDB/IPDBRawSymbol.h
include/llvm/DebugInfo/PDB/IPDBSession.h
include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h
include/llvm/DebugInfo/PDB/Native/NativeSession.h
include/llvm/DebugInfo/PDB/PDBSymbol.h
include/llvm/DebugInfo/PDB/PDBSymbolExe.h
include/llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h
include/llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h
include/llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h
include/llvm/DebugInfo/PDB/UDTLayout.h [new file with mode: 0644]
include/llvm/Support/Casting.h
lib/DebugInfo/PDB/CMakeLists.txt
lib/DebugInfo/PDB/DIA/DIARawSymbol.cpp
lib/DebugInfo/PDB/DIA/DIASession.cpp
lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
lib/DebugInfo/PDB/Native/NativeSession.cpp
lib/DebugInfo/PDB/PDBSymbol.cpp
lib/DebugInfo/PDB/PDBSymbolExe.cpp
lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp
lib/DebugInfo/PDB/UDTLayout.cpp [new file with mode: 0644]
test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test
test/DebugInfo/PDB/Inputs/symbolformat.pdb
test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp [new file with mode: 0644]
test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb [new file with mode: 0644]
test/tools/llvm-pdbdump/class-layout.test
test/tools/llvm-pdbdump/enum-layout.test
test/tools/llvm-pdbdump/simple-padding.test [new file with mode: 0644]
tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp
tools/llvm-pdbdump/PrettyClassDefinitionDumper.h
tools/llvm-pdbdump/PrettyFunctionDumper.cpp
tools/llvm-pdbdump/PrettyTypeDumper.cpp
tools/llvm-pdbdump/PrettyTypedefDumper.cpp
tools/llvm-pdbdump/PrettyVariableDumper.cpp
tools/llvm-pdbdump/PrettyVariableDumper.h
tools/llvm-pdbdump/llvm-pdbdump.cpp
tools/llvm-pdbdump/llvm-pdbdump.h
unittests/DebugInfo/PDB/PDBApiTest.cpp

index 1e40c46f8a27eb25e59a55174b6326ffdb48bf6c..c0633cbdfa5217977e1b1a64b977751d04e9237b 100644 (file)
@@ -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;
index 350442556bef88b176fbd45ee3b738bee6ae89f6..3f5818631e7bc1c9c1c56a868ab18fdf9da3b7a6 100644 (file)
@@ -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>
index 49866b8bb2f22eb5beef36881addb45bde430fca..4c28e194bc70d0188b062cb746b27da578138645 100644 (file)
@@ -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;
index 696736a907a6f260edec5d357e22e0d6a3eb801a..85d9fe1248599cb92a8bf2650923e18902601d1b 100644 (file)
@@ -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>
index 655bed9ac17c1815939d344f5b6263cc013d688b..cffb5d09d225bee3470da10cbccb6798fd390b36 100644 (file)
@@ -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;
index bbe207738e02115ce599ebef63051ecdf9faebac..e6da266f796d545a7c96f8b64f4b6ffa5c88e314 100644 (file)
@@ -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>
index 652f2136105650d00bc931b9b6eec83b3d4b70b4..b114b7afb0b03d86ff4365ebbd5caef28e793973 100644 (file)
@@ -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
index 5b3f50d153eb6078007570b1f497430c33403466..2c2d74665040e06ec2b82989f72369b012b6d0d5 100644 (file)
@@ -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;
index 0924efb8aa9c004f2d78db377a2f746e8ecca8ad..d607a3d8117028a397fb5b7e950721f2f9096d99 100644 (file)
@@ -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;
index 47a4525a47bac91f232c3526dcc7d217d9e586ba..e9e7fe8c9865ca44554d84dd9d7d383bec2026d6 100644 (file)
@@ -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;
index 17612ff460643ea08802486ac4326e2130ebeda7..e270c2b7eb952de7698b7f11c9f5f05f781547e2 100644 (file)
@@ -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/include/llvm/DebugInfo/PDB/UDTLayout.h b/include/llvm/DebugInfo/PDB/UDTLayout.h
new file mode 100644 (file)
index 0000000..20b7034
--- /dev/null
@@ -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
index 3a0c5536c01a4af07e291b5fc861778f0b69aede..89d2af052dc1656ae2b1b1e86aca7d024a975fe7 100644 (file)
@@ -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>
index 1295d2a19ce26c5f138458cb631061279736fc58..f87a0b0a72e2f54c504e68320f8f7b2b282a17ad 100644 (file)
@@ -101,6 +101,7 @@ add_llvm_library(LLVMDebugInfoPDB
   PDBSymbolUnknown.cpp
   PDBSymbolUsingNamespace.cpp
   PDBSymDumper.cpp
+  UDTLayout.cpp
   ${PDB_IMPL_SOURCES}
 
   ADDITIONAL_HEADER_DIRS
index 6182dab213c448cc1725b80e0ea58554ae427a95..5e8c0bdc171d511ee354d94c20f85ddb305b0136 100644 (file)
@@ -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);
index 7077bda4a534795c9492bef4c021efaac1700d56..6ecf335812b5380f899760aae5c6a6b89f2300fa 100644 (file)
@@ -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;
index 4841ded7410268533ba5e720e8a79aad999d282b..3aba35adb53f75f68b17ecb8cc00f599fd63c6d5 100644 (file)
@@ -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;
 }
index 3a83a326cfe63bee7b39b57fb2e53bfb8e3acd15..7e6843bceb7db330d0d3770951ef944b1c92e142 100644 (file)
@@ -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()));
index 2c8438f9c23416ecfdc1039b4c698a04ea1b0cec..14eb6ba8ad8d1fa35584f6faa35f7fbafd805550 100644 (file)
@@ -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);
 }
index b9fcac78c36d721d4725e55bc967cd8817c6904a..7417167b61ade28ecba6d115d34157da7f26cc8b 100644 (file)
@@ -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;
+}
index 4a9a9ed5fda8e82c5648c8102fb09e18a382a632..15dc153521656d865514cb15c4e0ba779af2e23f 100644 (file)
@@ -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/lib/DebugInfo/PDB/UDTLayout.cpp b/lib/DebugInfo/PDB/UDTLayout.cpp
new file mode 100644 (file)
index 0000000..71443fe
--- /dev/null
@@ -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
index 60a195346875d9f9ce8b0212d4a4ac928d12d01d..0bb3e001d3a43e580583afeb4f6ef87624333ebe 100644 (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
index 0e509f3a93c33fa65471692bb69155effebdb7d4..9272f318258bc06dc115475b9e0d4188edd75331 100644 (file)
Binary files a/test/DebugInfo/PDB/Inputs/symbolformat.pdb and b/test/DebugInfo/PDB/Inputs/symbolformat.pdb differ
diff --git a/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp b/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.cpp
new file mode 100644 (file)
index 0000000..b10839b
--- /dev/null
@@ -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/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb b/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb
new file mode 100644 (file)
index 0000000..44207d6
Binary files /dev/null and b/test/tools/llvm-pdbdump/Inputs/SimplePaddingTest.pdb differ
index e2921d298fce2ab16618a8ef7d0e688b794f6ac6..c0083d176eac76e8652a7202ddd42c29862505be 100644 (file)
 ; 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
index 21e1867175f6b628bc66c1c7f5ae201d02ebfa5b..df447c65bbae495dcdc78fd709047467feca77de 100644 (file)
@@ -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/test/tools/llvm-pdbdump/simple-padding.test b/test/tools/llvm-pdbdump/simple-padding.test
new file mode 100644 (file)
index 0000000..4096d28
--- /dev/null
@@ -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: }
index b48ed23c1c714e8cc281fa4c41f39495c6143db8..2e1e54e4db1af056c6b055cf66256c27349ee16b 100644 (file)
@@ -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);
index 8f0c35cba810f7558fca868d4e66e7f37be347f7..94ae07d345d16e2ceb552bce3484fc112530efa1 100644 (file)
@@ -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;
 };
 }
index 0e0da026e567814447c2540dc0cc98218787f794..b0be33c157ce687f2c1623ac74d88c5af1c7f160 100644 (file)
@@ -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;
index 12a47d24f79292d34713750d056a2be99db0630f..2857b07078cb0a4add275a8c8ebda3dacddac277 100644 (file)
 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 ";
index 861f7e28b3858741a6398b916b878daa5c33cb99..2d8e915d76043204c730439afcad10bef4af4967 100644 (file)
@@ -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;
index 65f0139dfbc5d9c3e907bb9bfe175342e62aeac8..ef9a9b51bd018d00dd880d9dc4d612e0604d02a9 100644 (file)
@@ -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);
index eec389b170777205c74d8300674e7ecc64cf0649..ba9fdb176559c2bfbf4ed2276c6c4162404b3fa1 100644 (file)
@@ -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;
index 8a749bab98e8275b03f92def1ccfe000f728f141..a486c8a07308a9f3623d1f8a4ab961fe9a4c8f7e 100644 (file)
@@ -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));
index a335d30c4cf289e52d62b6dc4ee015ee186b3720..c572176f76da514ec52bed757cd40d277d0e29c0 100644 (file)
@@ -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;
index ba09a8e28424a66414ca825e0a42796a641cb668..6afe83cd90dd51339decda4634f3034455b0ca4e 100644 (file)
@@ -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)