[PDB] Parse UDT symbols and pointers to members (combined patch)
authorAleksandr Urakov <aleksandr.urakov@jetbrains.com>
Tue, 14 Aug 2018 07:57:44 +0000 (07:57 +0000)
committerAleksandr Urakov <aleksandr.urakov@jetbrains.com>
Tue, 14 Aug 2018 07:57:44 +0000 (07:57 +0000)
Summary:
In this patch I've tried to combine the best ideas from D49368 and D49410,
so it implements following:

- Completion of UDTs from a PDB with a filling of a layout info;
- Pointers to members;
- Fixes the bug relating to a virtual base offset reading from `vbtable`.
  The offset was treated as an unsigned, but it can be a negative sometimes.
- Support of MSInheritance attribute

Reviewers: asmith, zturner, rnk, labath, clayborg, lldb-commits

Reviewed By: zturner

Subscribers: aleksandr.urakov, stella.stamenova, JDevlieghere, lldb-commits

Differential Revision: https://reviews.llvm.org/D49980

llvm-svn: 339649

13 files changed:
lldb/include/lldb/Symbol/ClangASTContext.h
lldb/lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp [new file with mode: 0644]
lldb/lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp [new file with mode: 0644]
lldb/lit/SymbolFile/PDB/Inputs/UdtLayoutTest.cpp [new file with mode: 0644]
lldb/lit/SymbolFile/PDB/Inputs/UdtLayoutTest.script [new file with mode: 0644]
lldb/lit/SymbolFile/PDB/class-layout.test [new file with mode: 0644]
lldb/lit/SymbolFile/PDB/pointers.test [new file with mode: 0644]
lldb/lit/SymbolFile/PDB/udt-layout.test [new file with mode: 0644]
lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp
lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h
lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
lldb/source/Symbol/ClangASTContext.cpp

index 9364149..ac77ab1 100644 (file)
@@ -831,6 +831,8 @@ public:
                            bool is_static, bool is_inline, bool is_explicit,
                            bool is_attr_used, bool is_artificial);
 
+  void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type);
+
   // C++ Base Classes
   clang::CXXBaseSpecifier *
   CreateBaseClassSpecifier(lldb::opaque_compiler_type_t type,
diff --git a/lldb/lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp b/lldb/lit/SymbolFile/PDB/Inputs/ClassLayoutTest.cpp
new file mode 100644 (file)
index 0000000..3c4b005
--- /dev/null
@@ -0,0 +1,111 @@
+// To avoid linking MSVC specific libs, we don't test virtual/override methods
+// that needs vftable support in this file.
+
+// Enum.
+enum Enum { RED, GREEN, BLUE };
+Enum EnumVar;
+
+// Union.
+union Union {
+  short Row;
+  unsigned short Col;
+  int Line : 16; // Test named bitfield.
+  short : 8;     // Unnamed bitfield symbol won't be generated in PDB.
+  long Table;
+};
+Union UnionVar;
+
+// Struct.
+struct Struct;
+typedef Struct StructTypedef;
+
+struct Struct {
+  bool A;
+  unsigned char UCharVar;
+  unsigned int UIntVar;
+  long long LongLongVar;
+  Enum EnumVar; // Test struct has UDT member.
+  int array[10];
+};
+struct Struct StructVar;
+
+struct _List; // Forward declaration.
+struct Complex {
+  struct _List *array[90];
+  struct { // Test unnamed struct. MSVC treats it as `int x`
+    int x;
+  };
+  union { // Test unnamed union. MSVC treats it as `int a; float b;`
+    int a;
+    float b;
+  };
+};
+struct Complex c;
+
+struct _List { // Test doubly linked list.
+  struct _List *current;
+  struct _List *previous;
+  struct _List *next;
+};
+struct _List ListVar;
+
+typedef struct {
+  int a;
+} UnnamedStruct; // Test unnamed typedef-ed struct.
+UnnamedStruct UnnanmedVar;
+
+// Class.
+namespace MemberTest {
+class Base {
+public:
+  Base() {}
+  ~Base() {}
+
+public:
+  int Get() { return 0; }
+
+protected:
+  int a;
+};
+class Friend {
+public:
+  int f() { return 3; }
+};
+class Class : public Base { // Test base class.
+  friend Friend;
+  static int m_static; // Test static member variable.
+public:
+  Class() : m_public(), m_private(), m_protected() {}
+  explicit Class(int a) { m_public = a; } // Test first reference of m_public.
+  ~Class() {}
+
+  static int StaticMemberFunc(int a, ...) {
+    return 1;
+  } // Test static member function.
+  int Get() { return 1; }
+  int f(Friend c) { return c.f(); }
+  inline bool operator==(const Class &rhs) const // Test operator.
+  {
+    return (m_public == rhs.m_public);
+  }
+
+public:
+  int m_public;
+  struct Struct m_struct;
+
+private:
+  Union m_union;
+  int m_private;
+
+protected:
+  friend class Friend;
+  int m_protected;
+};
+} // namespace MemberTest
+
+int main() {
+  MemberTest::Base B1;
+  B1.Get();
+  MemberTest::Class::StaticMemberFunc(1, 10, 2);
+  return 0;
+}
diff --git a/lldb/lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp b/lldb/lit/SymbolFile/PDB/Inputs/PointerTypeTest.cpp
new file mode 100644 (file)
index 0000000..6612c30
--- /dev/null
@@ -0,0 +1,23 @@
+int main() {
+  // Test pointer to array.
+  int array[2][4];
+  int(*array_pointer)[2][4] = &array;
+
+  struct ST {
+    int a;
+    int f(int x) { return 1; }
+  };
+
+  ST s = {10};
+
+  // Test pointer to a local.
+  int *p_int = &s.a;
+
+  // Test pointer to data member.
+  int ST::*p_member_field = &ST::a;
+
+  // Test pointer to member function.
+  int (ST::*p_member_method)(int) = &ST::f;
+
+  return 0;
+}
diff --git a/lldb/lit/SymbolFile/PDB/Inputs/UdtLayoutTest.cpp b/lldb/lit/SymbolFile/PDB/Inputs/UdtLayoutTest.cpp
new file mode 100644 (file)
index 0000000..59a4fc5
--- /dev/null
@@ -0,0 +1,61 @@
+struct A {
+  explicit A(int u) { _u._u3 = u; }
+  A(const A &) = default;
+  virtual ~A() = default;
+
+private:
+  union U {
+    char _u1;
+    short _u2;
+    int _u3;
+  };
+
+  A::U _u;
+};
+
+#pragma pack(push, 1)
+template <int I> struct B : public virtual A {
+  B(char a, unsigned short b, int c) : A(a + b + c), _a(a), _b(b), _c(c) {}
+
+private:
+  char _a;
+  unsigned short : 3;
+  unsigned short _b : 6;
+  unsigned short : 4;
+  int _c;
+};
+#pragma pack(pop)
+
+#pragma pack(push, 16)
+class C : private virtual B<0>, public virtual B<1>, private B<2>, public B<3> {
+public:
+  C(char x, char y, char z)
+      : A(x - y + z), B<0>(x, y, z), B<1>(x * 2, y * 2, z * 2),
+        B<2>(x * 3, y * 3, z * 3), B<3>(x * 4, y * 4, z * 4), _x(x * 5),
+        _y(y * 5), _z(z * 5) {}
+
+  static int abc;
+
+private:
+  int _x;
+  short _y;
+  char _z;
+};
+int C::abc = 123;
+#pragma pack(pop)
+
+class List {
+public:
+  List() = default;
+  List(List *p, List *n, C v) : Prev(p), Next(n), Value(v) {}
+
+private:
+  List *Prev = nullptr;
+  List *Next = nullptr;
+  C Value{1, 2, 3};
+};
+
+int main() {
+  List ls[16];
+  return 0;
+}
diff --git a/lldb/lit/SymbolFile/PDB/Inputs/UdtLayoutTest.script b/lldb/lit/SymbolFile/PDB/Inputs/UdtLayoutTest.script
new file mode 100644 (file)
index 0000000..91de55f
--- /dev/null
@@ -0,0 +1,4 @@
+breakpoint set --file UdtLayoutTest.cpp --line 60
+run
+target variable
+frame variable
diff --git a/lldb/lit/SymbolFile/PDB/class-layout.test b/lldb/lit/SymbolFile/PDB/class-layout.test
new file mode 100644 (file)
index 0000000..b5204bf
--- /dev/null
@@ -0,0 +1,92 @@
+REQUIRES: windows
+RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/ClassLayoutTest.cpp /o %T/ClassLayoutTest.cpp.obj
+RUN: link %T/ClassLayoutTest.cpp.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/ClassLayoutTest.cpp.exe
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=ENUM %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=UNION %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=STRUCT %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=COMPLEX %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=LIST %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=UNNAMED-STRUCT %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=BASE %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=FRIEND %s
+RUN: lldb-test symbols %T/ClassLayoutTest.cpp.exe | FileCheck --check-prefix=CLASS %s
+
+CHECK: Module [[MOD:.*]]
+CHECK: {{^[0-9A-F]+}}: SymbolVendor ([[MOD]])
+CHECK: {{^[0-9A-F]+}}:   CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\ClassLayoutTest.cpp'
+
+ENUM:  name = "Enum", size = 4,  decl = ClassLayoutTest.cpp:5
+ENUM-SAME: enum Enum {
+ENUM:    RED,
+ENUM:    GREEN,
+ENUM:    BLUE
+ENUM:}
+
+UNION:  name = "Union", size = 4, decl = ClassLayoutTest.cpp:9
+UNION-SAME: union Union {
+UNION:    short Row;
+UNION:    unsigned short Col;
+UNION:    int Line : 16;
+UNION:    long Table;
+UNION:}
+
+STRUCT:  name = "Struct", size = 64, decl = ClassLayoutTest.cpp:22
+STRUCT-SAME: struct Struct {
+STRUCT:    bool A;
+STRUCT:    unsigned char UCharVar;
+STRUCT:    unsigned int UIntVar;
+STRUCT:    long long LongLongVar;
+STRUCT:    Enum EnumVar;
+STRUCT:    int array[10];
+STRUCT:}
+
+COMPLEX:  name = "Complex", size = 368, decl = ClassLayoutTest.cpp:33
+COMPLEX-SAME: struct Complex {
+COMPLEX:    _List *array[90];
+COMPLEX:    int x;
+COMPLEX:    int a;
+COMPLEX:    float b;
+COMPLEX:}
+
+LIST:  name = "_List", size = 12, decl = ClassLayoutTest.cpp:45
+LIST-SAME: struct _List {
+LIST:    _List *current;
+LIST:    _List *previous;
+LIST:    _List *next;
+LIST:}
+
+UNNAMED-STRUCT:  name = "UnnamedStruct", size = 4, decl = ClassLayoutTest.cpp:52
+UNNAMED-STRUCT-SAME: struct UnnamedStruct {
+UNNAMED-STRUCT:   int a;
+UNNAMED-STRUCT:}
+
+BASE:  name = "MemberTest::Base", size = 4,  decl = ClassLayoutTest.cpp:59
+BASE-SAME: class MemberTest::Base {
+BASE:    int a;
+BASE:    void {{.*}}Base();
+BASE:    {{.*}}~Base();
+BASE:    int {{.*}}Get();
+BASE:}
+
+FRIEND:  name = "MemberTest::Friend", size = 1, decl = ClassLayoutTest.cpp:70
+FRIEND-SAME: class MemberTest::Friend {
+FRIEND:    int f();
+FRIEND: }
+
+CLASS:  name = "MemberTest::Class", size = 88, decl = ClassLayoutTest.cpp:74
+CLASS-SAME: class MemberTest::Class : public MemberTest::Base {
+CLASS:    static int m_static;
+CLASS:    int m_public;
+CLASS:    Struct m_struct;
+CLASS:    Union m_union;
+CLASS:    int m_private;
+CLASS:    int m_protected;
+CLASS:    void Class();
+CLASS:    void Class(int);
+CLASS:    ~MemberTest::Class();
+CLASS:    static int {{.*}}StaticMemberFunc(int, ...);
+CLASS:    int Get();
+CLASS:    int f(MemberTest::Friend);
+CLASS:    bool operator==(const MemberTest::Class &)
+CLASS:}
diff --git a/lldb/lit/SymbolFile/PDB/pointers.test b/lldb/lit/SymbolFile/PDB/pointers.test
new file mode 100644 (file)
index 0000000..48cdf4d
--- /dev/null
@@ -0,0 +1,38 @@
+REQUIRES: windows
+RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/PointerTypeTest.cpp /o %T/PointerTypeTest.cpp.obj
+RUN: link %T/PointerTypeTest.cpp.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/PointerTypeTest.cpp.exe
+RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck %s
+RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck --check-prefix=MAIN-ST-F %s
+RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck --check-prefix=MAIN-ST %s
+RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck --check-prefix=MAIN %s
+RUN: lldb-test symbols %T/PointerTypeTest.cpp.exe | FileCheck --check-prefix=F %s
+
+CHECK: Module [[MOD:.*]]
+CHECK: {{^[0-9A-F]+}}:   CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\PointerTypeTest.cpp'
+
+MAIN-ST-F:  name = "main::ST::f"
+MAIN-ST-F-SAME: decl = PointerTypeTest.cpp:8
+MAIN-ST-F-SAME: compiler_type = {{.*}} int (int)
+
+MAIN-ST:  name = "main::ST", size = 4, decl = PointerTypeTest.cpp:6, compiler_type = {{.*}} struct main::ST {
+MAIN-ST-NEXT: int a;
+MAIN-ST-NEXT: int {{.*}}f(int);
+MAIN-ST-NEXT:}
+
+MAIN:   Function{[[FID1:.*]]}, mangled = _main
+MAIN-NEXT:  Block{[[FID1]]}
+MAIN:     Variable{{.*}}, name = "array_pointer"
+MAIN-SAME:    (int (*)[2][4]), scope = local
+MAIN:     Variable{{.*}}, name = "p_int"
+MAIN-SAME:    (int *), scope = local
+MAIN:     Variable{{.*}}, name = "p_member_field"
+MAIN-SAME:    (int main::ST::*), scope = local
+MAIN:     Variable{{.*}}, name = "p_member_method"
+MAIN-SAME:    (int (main::ST::*)(int)), scope = local
+
+F:   Function{[[FID2:.*]]}, demangled = {{.*}}f(int)
+F-NEXT:  Block{[[FID2]]}
+F:     Variable{{.*}}, name = "this"
+F-SAME:    (main::ST *), scope = parameter, location = {{.*}}, artificial
+F:     Variable{{.*}}, name = "x"
+F-SAME:    (int), scope = parameter, decl = PointerTypeTest.cpp:8
diff --git a/lldb/lit/SymbolFile/PDB/udt-layout.test b/lldb/lit/SymbolFile/PDB/udt-layout.test
new file mode 100644 (file)
index 0000000..3bca687
--- /dev/null
@@ -0,0 +1,51 @@
+REQUIRES: windows
+RUN: clang-cl /Zi %S/Inputs/UdtLayoutTest.cpp /o %t.exe
+RUN: %lldb -b -s %S/Inputs/UdtLayoutTest.script -- %t.exe | FileCheck %s
+
+CHECK:(int) int C::abc = 123
+CHECK:(List [16]) ls = {
+CHECK:  [15] = {
+CHECK:    Prev = 0x00000000
+CHECK:    Next = 0x00000000
+CHECK:    Value = {
+CHECK:      B<0> = {
+CHECK:        A = {
+CHECK:          _u = (_u1 = '\x02', _u2 = 2, _u3 = 2)
+CHECK:        }
+CHECK:        _a = '\x01'
+CHECK:        _b = 2
+CHECK:        _c = 3
+CHECK:      }
+CHECK:      B<1> = {
+CHECK:        A = {
+CHECK:          _u = (_u1 = '\x02', _u2 = 2, _u3 = 2)
+CHECK:        }
+CHECK:        _a = '\x02'
+CHECK:        _b = 4
+CHECK:        _c = 6
+CHECK:      }
+CHECK:      B<2> = {
+CHECK:        A = {
+CHECK:          _u = (_u1 = '\x02', _u2 = 2, _u3 = 2)
+CHECK:        }
+CHECK:        _a = '\x03'
+CHECK:        _b = 6
+CHECK:        _c = 9
+CHECK:      }
+CHECK:      B<3> = {
+CHECK:        A = {
+CHECK:          _u = (_u1 = '\x02', _u2 = 2, _u3 = 2)
+CHECK:        }
+CHECK:        _a = '\x04'
+CHECK:        _b = 8
+CHECK:        _c = 12
+CHECK:      }
+CHECK:      A = {
+CHECK:        _u = (_u1 = '\x02', _u2 = 2, _u3 = 2)
+CHECK:      }
+CHECK:      _x = 5
+CHECK:      _y = 10
+CHECK:      _z = '\x0f'
+CHECK:    }
+CHECK:  }
+CHECK:}
index 833cc66..2955d38 100644 (file)
@@ -2094,95 +2094,6 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos(
   return template_param_infos.args.size() == template_param_infos.names.size();
 }
 
-// Checks whether m1 is an overload of m2 (as opposed to an override). This is
-// called by addOverridesForMethod to distinguish overrides (which share a
-// vtable entry) from overloads (which require distinct entries).
-static bool isOverload(clang::CXXMethodDecl *m1, clang::CXXMethodDecl *m2) {
-  // FIXME: This should detect covariant return types, but currently doesn't.
-  lldbassert(&m1->getASTContext() == &m2->getASTContext() &&
-             "Methods should have the same AST context");
-  clang::ASTContext &context = m1->getASTContext();
-
-  const auto *m1Type =
-    llvm::cast<clang::FunctionProtoType>(
-      context.getCanonicalType(m1->getType()));
-
-  const auto *m2Type =
-    llvm::cast<clang::FunctionProtoType>(
-      context.getCanonicalType(m2->getType()));
-
-  auto compareArgTypes =
-    [&context](const clang::QualType &m1p, const clang::QualType &m2p) {
-      return context.hasSameType(m1p.getUnqualifiedType(),
-                                 m2p.getUnqualifiedType());
-    };
-
-  // FIXME: In C++14 and later, we can just pass m2Type->param_type_end()
-  //        as a fourth parameter to std::equal().
-  return (m1->getNumParams() != m2->getNumParams()) ||
-         !std::equal(m1Type->param_type_begin(), m1Type->param_type_end(),
-                     m2Type->param_type_begin(), compareArgTypes);
-}
-
-// If decl is a virtual method, walk the base classes looking for methods that
-// decl overrides. This table of overridden methods is used by IRGen to
-// determine the vtable layout for decl's parent class.
-static void addOverridesForMethod(clang::CXXMethodDecl *decl) {
-  if (!decl->isVirtual())
-    return;
-
-  clang::CXXBasePaths paths;
-
-  auto find_overridden_methods =
-    [decl](const clang::CXXBaseSpecifier *specifier, clang::CXXBasePath &path) {
-      if (auto *base_record =
-          llvm::dyn_cast<clang::CXXRecordDecl>(
-            specifier->getType()->getAs<clang::RecordType>()->getDecl())) {
-
-        clang::DeclarationName name = decl->getDeclName();
-
-        // If this is a destructor, check whether the base class destructor is
-        // virtual.
-        if (name.getNameKind() == clang::DeclarationName::CXXDestructorName)
-          if (auto *baseDtorDecl = base_record->getDestructor()) {
-            if (baseDtorDecl->isVirtual()) {
-              path.Decls = baseDtorDecl;
-              return true;
-            } else
-              return false;
-          }
-
-        // Otherwise, search for name in the base class.
-        for (path.Decls = base_record->lookup(name); !path.Decls.empty();
-             path.Decls = path.Decls.slice(1)) {
-          if (auto *method_decl =
-                llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front()))
-            if (method_decl->isVirtual() && !isOverload(decl, method_decl)) {
-              path.Decls = method_decl;
-              return true;
-            }
-        }
-      }
-
-      return false;
-    };
-
-  if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) {
-    for (auto *overridden_decl : paths.found_decls())
-      decl->addOverriddenMethod(
-        llvm::cast<clang::CXXMethodDecl>(overridden_decl));
-  }
-}
-
-// If clang_type is a CXXRecordDecl, builds the method override list for each
-// of its virtual methods.
-static void addMethodOverrides(ClangASTContext &ast, CompilerType &clang_type) {
-  if (auto *record =
-      ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()))
-    for (auto *method : record->methods())
-      addOverridesForMethod(method);
-}
-
 bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die,
                                                 lldb_private::Type *type,
                                                 CompilerType &clang_type) {
@@ -2391,7 +2302,7 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die,
       }
     }
 
-    addMethodOverrides(m_ast, clang_type);
+    m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType());
     ClangASTContext::BuildIndirectFields(clang_type);
     ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
 
index 8bea994..713fa6e 100644 (file)
@@ -9,11 +9,15 @@
 
 #include "PDBASTParser.h"
 
+#include "SymbolFilePDB.h"
+
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 
+#include "lldb/Core/Module.h"
 #include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
 #include "lldb/Symbol/ClangUtil.h"
 #include "lldb/Symbol/Declaration.h"
 #include "lldb/Symbol/SymbolFile.h"
@@ -48,8 +52,9 @@ int TranslateUdtKind(PDB_UdtType pdb_kind) {
     return clang::TTK_Union;
   case PDB_UdtType::Interface:
     return clang::TTK_Interface;
+  default:
+    llvm_unreachable("unsuported PDB UDT type");
   }
-  return -1;
 }
 
 lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) {
@@ -199,6 +204,68 @@ bool GetDeclarationForSymbol(const PDBSymbol &symbol, Declaration &decl) {
   decl.SetLine(first_line_up->getLineNumber());
   return true;
 }
+
+AccessType TranslateMemberAccess(PDB_MemberAccess access) {
+  switch (access) {
+  case PDB_MemberAccess::Private:
+    return eAccessPrivate;
+  case PDB_MemberAccess::Protected:
+    return eAccessProtected;
+  case PDB_MemberAccess::Public:
+    return eAccessPublic;
+  default:
+    return eAccessNone;
+  }
+}
+
+AccessType GetDefaultAccessibilityForUdtKind(PDB_UdtType udt_kind) {
+  switch (udt_kind) {
+  case PDB_UdtType::Struct:
+  case PDB_UdtType::Union:
+    return eAccessPublic;
+  case PDB_UdtType::Class:
+  case PDB_UdtType::Interface:
+    return eAccessPrivate;
+  default:
+    llvm_unreachable("unsupported PDB UDT type");
+  }
+}
+
+AccessType GetAccessibilityForUdt(const PDBSymbolTypeUDT &udt) {
+  AccessType access = TranslateMemberAccess(udt.getAccess());
+  if (access != lldb::eAccessNone || !udt.isNested())
+    return access;
+
+  auto parent = udt.getClassParent();
+  if (!parent)
+    return lldb::eAccessNone;
+
+  auto parent_udt = llvm::dyn_cast<PDBSymbolTypeUDT>(parent.get());
+  if (!parent_udt)
+    return lldb::eAccessNone;
+
+  return GetDefaultAccessibilityForUdtKind(parent_udt->getUdtKind());
+}
+
+clang::MSInheritanceAttr::Spelling GetMSInheritance(
+    const PDBSymbolTypeUDT &udt) {
+  int base_count = 0;
+  bool has_virtual = false;
+
+  auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>();
+  if (bases_enum) {
+    while (auto base = bases_enum->getNext()) {
+      base_count++;
+      has_virtual |= base->isVirtualBaseClass();
+    }
+  }
+
+  if (has_virtual)
+    return clang::MSInheritanceAttr::Keyword_virtual_inheritance;
+  if (base_count > 1)
+    return clang::MSInheritanceAttr::Keyword_multiple_inheritance;
+  return clang::MSInheritanceAttr::Keyword_single_inheritance;
+}
 } // namespace
 
 PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {}
@@ -216,29 +283,90 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
   Declaration decl;
 
   switch (type.getSymTag()) {
+  case PDB_SymType::BaseClass: {
+    auto symbol_file = m_ast.GetSymbolFile();
+    if (!symbol_file)
+      return nullptr;
+
+    auto ty = symbol_file->ResolveTypeUID(type.getRawSymbol().getTypeId());
+    return ty ? ty->shared_from_this() : nullptr;
+  } break;
   case PDB_SymType::UDT: {
     auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(&type);
     assert(udt);
-    AccessType access = lldb::eAccessPublic;
-    PDB_UdtType udt_kind = udt->getUdtKind();
-    auto tag_type_kind = TranslateUdtKind(udt_kind);
-    if (tag_type_kind == -1)
+
+    // Note that, unnamed UDT being typedef-ed is generated as a UDT symbol
+    // other than a Typedef symbol in PDB. For example,
+    //    typedef union { short Row; short Col; } Union;
+    // is generated as a named UDT in PDB:
+    //    union Union { short Row; short Col; }
+    // Such symbols will be handled here.
+
+    // Some UDT with trival ctor has zero length. Just ignore.
+    if (udt->getLength() == 0)
+      return nullptr;
+
+    // Ignore unnamed-tag UDTs.
+    if (udt->getName().empty())
       return nullptr;
 
-    if (udt_kind == PDB_UdtType::Class)
-      access = lldb::eAccessPrivate;
+    auto access = GetAccessibilityForUdt(*udt);
+
+    auto tag_type_kind = TranslateUdtKind(udt->getUdtKind());
+
+    ClangASTMetadata metadata;
+    metadata.SetUserID(type.getSymIndexId());
+    metadata.SetIsDynamicCXXType(false);
 
     CompilerType clang_type = m_ast.CreateRecordType(
         tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind,
-        lldb::eLanguageTypeC_plus_plus, nullptr);
+        lldb::eLanguageTypeC_plus_plus, &metadata);
+    assert(clang_type.IsValid());
+
+    if (udt->isConstType())
+      clang_type = clang_type.AddConstModifier();
+
+    if (udt->isVolatileType())
+      clang_type = clang_type.AddVolatileModifier();
+
+    clang::CXXRecordDecl *record_decl =
+      m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
+    assert(record_decl);
+    auto inheritance_attr = clang::MSInheritanceAttr::CreateImplicit(
+        *m_ast.getASTContext(), GetMSInheritance(*udt));
+    record_decl->addAttr(inheritance_attr);
+
+    ClangASTContext::StartTagDeclarationDefinition(clang_type);
 
-    m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
+    Type::ResolveStateTag type_resolve_state_tag;
+    auto children = udt->findAllChildren();
+    if (!children || children->getChildCount() == 0) {
+      // PDB does not have symbol of forwarder. We assume we get an udt w/o any
+      // fields. Just complete it at this point.
+      ClangASTContext::CompleteTagDeclarationDefinition(clang_type);
 
+      m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), false);
+
+      type_resolve_state_tag = Type::eResolveStateFull;
+    } else {
+      // Add the type to the forward declarations. It will help us to avoid
+      // an endless recursion in CompleteTypeFromUdt function.
+      auto clang_type_removed_fast_quals =
+          ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType();
+      m_forward_decl_clang_type_to_uid[clang_type_removed_fast_quals] =
+          type.getSymIndexId();
+
+      m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true);
+
+      type_resolve_state_tag = Type::eResolveStateForward;
+    }
+
+    GetDeclarationForSymbol(type, decl);
     return std::make_shared<lldb_private::Type>(
         type.getSymIndexId(), m_ast.GetSymbolFile(),
         ConstString(udt->getName()), udt->getLength(), nullptr,
         LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type,
-        lldb_private::Type::eResolveStateForward);
+        type_resolve_state_tag);
   } break;
   case PDB_SymType::Enum: {
     auto enum_type = llvm::dyn_cast<PDBSymbolTypeEnum>(&type);
@@ -441,6 +569,26 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
     if (!pointee_type)
       return nullptr;
 
+    if (pointer_type->isPointerToDataMember() ||
+        pointer_type->isPointerToMemberFunction()) {
+      auto class_parent_uid = pointer_type->getRawSymbol().getClassParentId();
+      auto class_parent_type =
+          m_ast.GetSymbolFile()->ResolveTypeUID(class_parent_uid);
+      assert(class_parent_type);
+
+      CompilerType pointer_ast_type;
+      pointer_ast_type = ClangASTContext::CreateMemberPointerType(
+          class_parent_type->GetLayoutCompilerType(),
+          pointee_type->GetForwardCompilerType());
+      assert(pointer_ast_type);
+
+      return std::make_shared<lldb_private::Type>(
+          pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(),
+          pointer_type->getLength(), nullptr, LLDB_INVALID_UID,
+          lldb_private::Type::eEncodingIsUID, decl, pointer_ast_type,
+          lldb_private::Type::eResolveStateForward);
+    }
+
     CompilerType pointer_ast_type;
     pointer_ast_type = pointee_type->GetFullCompilerType();
     if (pointer_type->isReference())
@@ -471,6 +619,47 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) {
   return nullptr;
 }
 
+bool PDBASTParser::CompleteTypeFromPDB(
+    lldb_private::CompilerType &compiler_type) {
+  if (GetClangASTImporter().CanImport(compiler_type))
+    return GetClangASTImporter().CompleteType(compiler_type);
+
+  // Remove the type from the forward declarations to avoid
+  // an endless recursion for types like a linked list.
+  CompilerType compiler_type_no_qualifiers =
+      ClangUtil::RemoveFastQualifiers(compiler_type);
+  auto uid_it = m_forward_decl_clang_type_to_uid.find(
+      compiler_type_no_qualifiers.GetOpaqueQualType());
+  if (uid_it == m_forward_decl_clang_type_to_uid.end())
+    return true;
+
+  auto symbol_file = static_cast<SymbolFilePDB *>(m_ast.GetSymbolFile());
+  if (!symbol_file)
+    return false;
+
+  std::unique_ptr<PDBSymbol> symbol =
+      symbol_file->GetPDBSession().getSymbolById(uid_it->getSecond());
+  if (!symbol)
+    return false;
+
+  m_forward_decl_clang_type_to_uid.erase(uid_it);
+
+  ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
+                                         false);
+
+  switch (symbol->getSymTag()) {
+  case PDB_SymType::UDT: {
+    auto udt = llvm::dyn_cast<PDBSymbolTypeUDT>(symbol.get());
+    if (!udt)
+      return false;
+
+    return CompleteTypeFromUDT(*symbol_file, compiler_type, *udt);
+  }
+  default:
+    llvm_unreachable("not a forward clang type decl!");
+  }
+}
+
 bool PDBASTParser::AddEnumValue(CompilerType enum_type,
                                 const PDBSymbolData &enum_value) const {
   Declaration decl;
@@ -513,3 +702,187 @@ bool PDBASTParser::AddEnumValue(CompilerType enum_type,
       enum_type.GetOpaqueQualType(), underlying_type, decl, name.c_str(),
       raw_value, byte_size * 8);
 }
+
+bool PDBASTParser::CompleteTypeFromUDT(
+    lldb_private::SymbolFile &symbol_file,
+    lldb_private::CompilerType &compiler_type,
+    llvm::pdb::PDBSymbolTypeUDT &udt) {
+  ClangASTImporter::LayoutInfo layout_info;
+  layout_info.bit_size = udt.getLength() * 8;
+
+  auto nested_enums = udt.findAllChildren<PDBSymbolTypeUDT>();
+  if (nested_enums)
+    while (auto nested = nested_enums->getNext())
+      symbol_file.ResolveTypeUID(nested->getSymIndexId());
+
+  auto bases_enum = udt.findAllChildren<PDBSymbolTypeBaseClass>();
+  if (bases_enum)
+    AddRecordBases(symbol_file, compiler_type,
+                   TranslateUdtKind(udt.getUdtKind()), *bases_enum,
+                   layout_info);
+
+  auto members_enum = udt.findAllChildren<PDBSymbolData>();
+  if (members_enum)
+    AddRecordMembers(symbol_file, compiler_type, *members_enum, layout_info);
+
+  auto methods_enum = udt.findAllChildren<PDBSymbolFunc>();
+  if (methods_enum)
+    AddRecordMethods(symbol_file, compiler_type, *methods_enum);
+
+  m_ast.AddMethodOverridesForCXXRecordType(compiler_type.GetOpaqueQualType());
+  ClangASTContext::BuildIndirectFields(compiler_type);
+  ClangASTContext::CompleteTagDeclarationDefinition(compiler_type);
+
+  clang::CXXRecordDecl *record_decl =
+      m_ast.GetAsCXXRecordDecl(compiler_type.GetOpaqueQualType());
+  if (!record_decl)
+    return static_cast<bool>(compiler_type);
+
+  GetClangASTImporter().InsertRecordDecl(record_decl, layout_info);
+
+  return static_cast<bool>(compiler_type);
+}
+
+void PDBASTParser::AddRecordMembers(
+    lldb_private::SymbolFile &symbol_file,
+    lldb_private::CompilerType &record_type,
+    PDBDataSymbolEnumerator &members_enum,
+    lldb_private::ClangASTImporter::LayoutInfo &layout_info) const {
+  while (auto member = members_enum.getNext()) {
+    if (member->isCompilerGenerated())
+        continue;
+
+    auto member_name = member->getName();
+
+    auto member_type = symbol_file.ResolveTypeUID(member->getTypeId());
+    if (!member_type)
+      continue;
+
+    auto member_comp_type = member_type->GetLayoutCompilerType();
+    if (!member_comp_type.GetCompleteType()) {
+      symbol_file.GetObjectFile()->GetModule()->ReportError(
+          ":: Class '%s' has a member '%s' of type '%s' "
+          "which does not have a complete definition.",
+          record_type.GetTypeName().GetCString(), member_name.c_str(),
+          member_comp_type.GetTypeName().GetCString());
+      if (ClangASTContext::StartTagDeclarationDefinition(member_comp_type))
+        ClangASTContext::CompleteTagDeclarationDefinition(member_comp_type);
+    }
+
+    auto access = TranslateMemberAccess(member->getAccess());
+
+    switch (member->getDataKind()) {
+    case PDB_DataKind::Member: {
+      auto location_type = member->getLocationType();
+
+      auto bit_size = member->getLength();
+      if (location_type == PDB_LocType::ThisRel)
+        bit_size *= 8;
+
+      auto decl = ClangASTContext::AddFieldToRecordType(
+          record_type, member_name.c_str(), member_comp_type, access, bit_size);
+      if (!decl)
+        continue;
+
+      auto offset = member->getOffset() * 8;
+      if (location_type == PDB_LocType::BitField)
+        offset += member->getBitPosition();
+
+      layout_info.field_offsets.insert(std::make_pair(decl, offset));
+
+      break;
+    }
+    case PDB_DataKind::StaticMember:
+      ClangASTContext::AddVariableToRecordType(record_type, member_name.c_str(),
+                                               member_comp_type, access);
+      break;
+    default:
+      llvm_unreachable("unsupported PDB data kind");
+    }
+  }
+}
+
+void PDBASTParser::AddRecordBases(
+    lldb_private::SymbolFile &symbol_file,
+    lldb_private::CompilerType &record_type, int record_kind,
+    PDBBaseClassSymbolEnumerator &bases_enum,
+    lldb_private::ClangASTImporter::LayoutInfo &layout_info) const {
+  std::vector<clang::CXXBaseSpecifier *> base_classes;
+  while (auto base = bases_enum.getNext()) {
+    auto base_type = symbol_file.ResolveTypeUID(base->getTypeId());
+    if (!base_type)
+      continue;
+
+    auto base_comp_type = base_type->GetFullCompilerType();
+    if (!base_comp_type.GetCompleteType()) {
+      symbol_file.GetObjectFile()->GetModule()->ReportError(
+          ":: Class '%s' has a base class '%s' "
+          "which does not have a complete definition.",
+          record_type.GetTypeName().GetCString(),
+          base_comp_type.GetTypeName().GetCString());
+      if (ClangASTContext::StartTagDeclarationDefinition(base_comp_type))
+        ClangASTContext::CompleteTagDeclarationDefinition(base_comp_type);
+    }
+
+    auto access = TranslateMemberAccess(base->getAccess());
+
+    auto is_virtual = base->isVirtualBaseClass();
+
+    auto base_class_spec = m_ast.CreateBaseClassSpecifier(
+        base_comp_type.GetOpaqueQualType(), access, is_virtual,
+        record_kind == clang::TTK_Class);
+    if (!base_class_spec)
+        continue;
+
+    base_classes.push_back(base_class_spec);
+
+    if (is_virtual)
+        continue;
+
+    auto decl = m_ast.GetAsCXXRecordDecl(base_comp_type.GetOpaqueQualType());
+    if (!decl)
+      continue;
+
+    auto offset = clang::CharUnits::fromQuantity(base->getOffset());
+    layout_info.base_offsets.insert(std::make_pair(decl, offset));
+  }
+  if (!base_classes.empty()) {
+    m_ast.SetBaseClassesForClassType(record_type.GetOpaqueQualType(),
+                                     &base_classes.front(),
+                                     base_classes.size());
+    ClangASTContext::DeleteBaseClassSpecifiers(&base_classes.front(),
+                                               base_classes.size());
+  }
+}
+
+void PDBASTParser::AddRecordMethods(
+    lldb_private::SymbolFile &symbol_file,
+    lldb_private::CompilerType &record_type,
+    PDBFuncSymbolEnumerator &methods_enum) const {
+  while (auto method = methods_enum.getNext()) {
+    auto method_type = symbol_file.ResolveTypeUID(method->getSymIndexId());
+    // MSVC specific __vecDelDtor.
+    if (!method_type)
+      break;
+
+    auto method_comp_type = method_type->GetFullCompilerType();
+    if (!method_comp_type.GetCompleteType()) {
+      symbol_file.GetObjectFile()->GetModule()->ReportError(
+          ":: Class '%s' has a method '%s' whose type cannot be completed.",
+          record_type.GetTypeName().GetCString(),
+          method_comp_type.GetTypeName().GetCString());
+      if (ClangASTContext::StartTagDeclarationDefinition(method_comp_type))
+        ClangASTContext::CompleteTagDeclarationDefinition(method_comp_type);
+    }
+
+    // TODO: get mangled name for the method.
+    m_ast.AddMethodToCXXRecordType(
+        record_type.GetOpaqueQualType(), method->getName().c_str(),
+        /*mangled_name*/ nullptr, method_comp_type,
+        TranslateMemberAccess(method->getAccess()), method->isVirtual(),
+        method->isStatic(), method->hasInlineAttribute(),
+        /*is_explicit*/ false, // FIXME: Need this field in CodeView.
+        /*is_attr_used*/ false,
+        /*is_artificial*/ method->isCompilerGenerated());
+  }
+}
index d1ac138..5d18d0e 100644 (file)
@@ -28,9 +28,14 @@ class CompilerType;
 
 namespace llvm {
 namespace pdb {
+template <typename ChildType> class ConcreteSymbolEnumerator;
+
 class PDBSymbol;
 class PDBSymbolData;
+class PDBSymbolFunc;
+class PDBSymbolTypeBaseClass;
 class PDBSymbolTypeBuiltin;
+class PDBSymbolTypeUDT;
 } // namespace pdb
 } // namespace llvm
 
@@ -40,13 +45,46 @@ public:
   ~PDBASTParser();
 
   lldb::TypeSP CreateLLDBTypeFromPDBType(const llvm::pdb::PDBSymbol &type);
+  bool CompleteTypeFromPDB(lldb_private::CompilerType &compiler_type);
+
+  lldb_private::ClangASTImporter &GetClangASTImporter() {
+    return m_ast_importer;
+  }
 
 private:
+  typedef llvm::DenseMap<lldb::opaque_compiler_type_t, lldb::user_id_t>
+      ClangTypeToUidMap;
+  typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolData>
+      PDBDataSymbolEnumerator;
+  typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolTypeBaseClass>
+      PDBBaseClassSymbolEnumerator;
+  typedef llvm::pdb::ConcreteSymbolEnumerator<llvm::pdb::PDBSymbolFunc>
+      PDBFuncSymbolEnumerator;
+
   bool AddEnumValue(lldb_private::CompilerType enum_type,
                     const llvm::pdb::PDBSymbolData &data) const;
+  bool CompleteTypeFromUDT(lldb_private::SymbolFile &symbol_file,
+                           lldb_private::CompilerType &compiler_type,
+                           llvm::pdb::PDBSymbolTypeUDT &udt);
+  void AddRecordMembers(
+      lldb_private::SymbolFile &symbol_file,
+      lldb_private::CompilerType &record_type,
+      PDBDataSymbolEnumerator &members_enum,
+      lldb_private::ClangASTImporter::LayoutInfo &layout_info) const;
+  void AddRecordBases(
+      lldb_private::SymbolFile &symbol_file,
+      lldb_private::CompilerType &record_type,
+      int record_kind,
+      PDBBaseClassSymbolEnumerator &bases_enum,
+      lldb_private::ClangASTImporter::LayoutInfo &layout_info) const;
+  void AddRecordMethods(
+      lldb_private::SymbolFile &symbol_file,
+      lldb_private::CompilerType &record_type,
+      PDBFuncSymbolEnumerator &methods_enum) const;
 
   lldb_private::ClangASTContext &m_ast;
   lldb_private::ClangASTImporter m_ast_importer;
+  ClangTypeToUidMap m_forward_decl_clang_type_to_uid;
 };
 
 #endif // LLDB_PLUGINS_SYMBOLFILE_PDB_PDBASTPARSER_H
index 05f3017..d5b8817 100644 (file)
@@ -45,7 +45,7 @@
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
 
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" // For IsCPPMangledName
 #include "Plugins/SymbolFile/PDB/PDBASTParser.h"
 #include "Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h"
 
@@ -459,10 +459,13 @@ size_t SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) {
 
         // This should cause the type to get cached and stored in the `m_types`
         // lookup.
-        if (!ResolveTypeUID(symbol->getSymIndexId()))
-          continue;
-
-        ++num_added;
+        if (auto type = ResolveTypeUID(symbol->getSymIndexId())) {
+          // Resolve the type completely to avoid a completion
+          // (and so a list change, which causes an iterators invalidation)
+          // during a TypeList dumping
+          type->GetFullCompilerType();
+          ++num_added;
+        }
       }
     }
   };
@@ -568,8 +571,20 @@ lldb_private::Type *SymbolFilePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
 }
 
 bool SymbolFilePDB::CompleteType(lldb_private::CompilerType &compiler_type) {
-  // TODO: Implement this
-  return false;
+  std::lock_guard<std::recursive_mutex> guard(
+      GetObjectFile()->GetModule()->GetMutex());
+
+  ClangASTContext *clang_ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(
+      GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus));
+  if (!clang_ast_ctx)
+    return false;
+
+  PDBASTParser *pdb =
+      llvm::dyn_cast<PDBASTParser>(clang_ast_ctx->GetPDBParser());
+  if (!pdb)
+    return false;
+
+  return pdb->CompleteTypeFromPDB(compiler_type);
 }
 
 lldb_private::CompilerDecl SymbolFilePDB::GetDeclForUID(lldb::user_id_t uid) {
index 301b9b3..043aaa3 100644 (file)
@@ -124,6 +124,84 @@ ClangASTContextSupportsLanguage(lldb::LanguageType language) {
          // Use Clang for D until there is a proper language plugin for it
          language == eLanguageTypeD;
 }
+
+// Checks whether m1 is an overload of m2 (as opposed to an override). This is
+// called by addOverridesForMethod to distinguish overrides (which share a
+// vtable entry) from overloads (which require distinct entries).
+bool isOverload(clang::CXXMethodDecl *m1, clang::CXXMethodDecl *m2) {
+  // FIXME: This should detect covariant return types, but currently doesn't.
+  lldbassert(&m1->getASTContext() == &m2->getASTContext() &&
+             "Methods should have the same AST context");
+  clang::ASTContext &context = m1->getASTContext();
+
+  const auto *m1Type = llvm::cast<clang::FunctionProtoType>(
+      context.getCanonicalType(m1->getType()));
+
+  const auto *m2Type = llvm::cast<clang::FunctionProtoType>(
+      context.getCanonicalType(m2->getType()));
+
+  auto compareArgTypes = [&context](const clang::QualType &m1p,
+                                    const clang::QualType &m2p) {
+    return context.hasSameType(m1p.getUnqualifiedType(),
+                               m2p.getUnqualifiedType());
+  };
+
+  // FIXME: In C++14 and later, we can just pass m2Type->param_type_end()
+  //        as a fourth parameter to std::equal().
+  return (m1->getNumParams() != m2->getNumParams()) ||
+         !std::equal(m1Type->param_type_begin(), m1Type->param_type_end(),
+                     m2Type->param_type_begin(), compareArgTypes);
+}
+
+// If decl is a virtual method, walk the base classes looking for methods that
+// decl overrides. This table of overridden methods is used by IRGen to
+// determine the vtable layout for decl's parent class.
+void addOverridesForMethod(clang::CXXMethodDecl *decl) {
+  if (!decl->isVirtual())
+    return;
+
+  clang::CXXBasePaths paths;
+
+  auto find_overridden_methods =
+      [decl](const clang::CXXBaseSpecifier *specifier,
+             clang::CXXBasePath &path) {
+        if (auto *base_record = llvm::dyn_cast<clang::CXXRecordDecl>(
+                specifier->getType()->getAs<clang::RecordType>()->getDecl())) {
+
+          clang::DeclarationName name = decl->getDeclName();
+
+          // If this is a destructor, check whether the base class destructor is
+          // virtual.
+          if (name.getNameKind() == clang::DeclarationName::CXXDestructorName)
+            if (auto *baseDtorDecl = base_record->getDestructor()) {
+              if (baseDtorDecl->isVirtual()) {
+                path.Decls = baseDtorDecl;
+                return true;
+              } else
+                return false;
+            }
+
+          // Otherwise, search for name in the base class.
+          for (path.Decls = base_record->lookup(name); !path.Decls.empty();
+               path.Decls = path.Decls.slice(1)) {
+            if (auto *method_decl =
+                    llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front()))
+              if (method_decl->isVirtual() && !isOverload(decl, method_decl)) {
+                path.Decls = method_decl;
+                return true;
+              }
+          }
+        }
+
+        return false;
+      };
+
+  if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) {
+    for (auto *overridden_decl : paths.found_decls())
+      decl->addOverriddenMethod(
+          llvm::cast<clang::CXXMethodDecl>(overridden_decl));
+  }
+}
 }
 
 typedef lldb_private::ThreadSafeDenseMap<clang::ASTContext *, ClangASTContext *>
@@ -6371,7 +6449,7 @@ CompilerType ClangASTContext::GetChildCompilerTypeAtIndex(
   language_flags = 0;
 
   const bool idx_is_valid = idx < GetNumChildren(type, omit_empty_base_classes);
-  uint32_t bit_offset;
+  int32_t bit_offset;
   switch (parent_type_class) {
   case clang::Type::Builtin:
     if (idx_is_valid) {
@@ -6463,8 +6541,8 @@ CompilerType ClangASTContext::GetChildCompilerTypeAtIndex(
                                     cxx_record_decl, base_class_decl);
                             const lldb::addr_t base_offset_addr =
                                 vbtable_ptr + vbtable_index * 4;
-                            const uint32_t base_offset =
-                                process->ReadUnsignedIntegerFromMemory(
+                            const int32_t base_offset =
+                                process->ReadSignedIntegerFromMemory(
                                     base_offset_addr, 4, UINT32_MAX, err);
                             if (base_offset != UINT32_MAX) {
                               handled = true;
@@ -6488,8 +6566,8 @@ CompilerType ClangASTContext::GetChildCompilerTypeAtIndex(
                                 vtable_ptr + base_offset_offset.getQuantity();
                             const uint32_t base_offset_size =
                                 process->GetAddressByteSize();
-                            const uint64_t base_offset =
-                                process->ReadUnsignedIntegerFromMemory(
+                            const int64_t base_offset =
+                                process->ReadSignedIntegerFromMemory(
                                     base_offset_addr, base_offset_size,
                                     UINT32_MAX, err);
                             if (base_offset < UINT32_MAX) {
@@ -8127,6 +8205,13 @@ clang::CXXMethodDecl *ClangASTContext::AddMethodToCXXRecordType(
   return cxx_method_decl;
 }
 
+void ClangASTContext::AddMethodOverridesForCXXRecordType(
+    lldb::opaque_compiler_type_t type) {
+  if (auto *record = GetAsCXXRecordDecl(type))
+    for (auto *method : record->methods())
+      addOverridesForMethod(method);
+}
+
 #pragma mark C++ Base Classes
 
 clang::CXXBaseSpecifier *
@@ -9666,11 +9751,16 @@ bool ClangASTContext::LayoutRecordType(
     llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
         &vbase_offsets) {
   ClangASTContext *ast = (ClangASTContext *)baton;
-  DWARFASTParserClang *dwarf_ast_parser =
-      (DWARFASTParserClang *)ast->GetDWARFParser();
-  return dwarf_ast_parser->GetClangASTImporter().LayoutRecordType(
-      record_decl, bit_size, alignment, field_offsets, base_offsets,
-      vbase_offsets);
+  lldb_private::ClangASTImporter *importer = nullptr;
+  if (ast->m_dwarf_ast_parser_ap)
+    importer = &ast->m_dwarf_ast_parser_ap->GetClangASTImporter();
+  if (!importer && ast->m_pdb_ast_parser_ap)
+    importer = &ast->m_pdb_ast_parser_ap->GetClangASTImporter();
+  if (!importer)
+    return false;
+
+  return importer->LayoutRecordType(record_decl, bit_size, alignment,
+                                    field_offsets, base_offsets, vbase_offsets);
 }
 
 //----------------------------------------------------------------------