zturner created this revision.
zturner added reviewers: lemo, aleksandr.urakov.

Previous patches added support for dumpign global variables of builtin types, 
so this patch does the same for class types.

For the most part, everything just worked, there was only one minor bug fix 
needed, which was that when a variable is of a modified class type (const, 
volatile, etc), we can't resolve the forward decl in `CreateAndCacheType`, so 
when it comes time to call `CompleteType`, one of our asserts was firing 
because we expected a Class, Struct, Enum, or Union, but we were getting an 
`LF_MODIFIER`.  The other issue was that one of my tests added an array member, 
and we hadn't yet handled them, so I just went ahead and handled them since it 
was easy.

There's probably room for lots of interesting test cases here, but these are 
the ones I was able to come up with.


https://reviews.llvm.org/D53822

Files:
  lldb/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
  lldb/lit/SymbolFile/NativePDB/global-classes.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h

Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -170,6 +170,8 @@
                              const llvm::codeview::EnumRecord &er);
   lldb::TypeSP CreateTagType(PdbSymUid type_uid,
                              const llvm::codeview::UnionRecord &ur);
+  lldb::TypeSP CreateArrayType(PdbSymUid type_uid,
+                               const llvm::codeview::ArrayRecord &ar);
   lldb::TypeSP
   CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size,
                          clang::TagTypeKind ttk,
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -391,9 +391,7 @@
   // If this is an LF_MODIFIER, look through it to get the kind that it
   // modifies.  Note that it's not possible to have an LF_MODIFIER that
   // modifies another LF_MODIFIER, although this would handle that anyway.
-  ModifierRecord mr;
-  llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mr));
-  return GetPdbSymType(tpi, mr.ModifiedType);
+  return GetPdbSymType(tpi, LookThroughModifierRecord(cvt));
 }
 
 static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
@@ -774,6 +772,25 @@
       lldb_private::Type::eResolveStateForward);
 }
 
+TypeSP SymbolFileNativePDB::CreateArrayType(PdbSymUid type_uid,
+                                            const ArrayRecord &ar) {
+  TypeSP element_type = GetOrCreateType(ar.ElementType);
+  uint64_t element_count = ar.Size / element_type->GetByteSize();
+
+  CompilerType element_ct = element_type->GetFullCompilerType();
+
+  CompilerType array_ct =
+      m_clang->CreateArrayType(element_ct, element_count, false);
+
+  Declaration decl;
+  TypeSP array_sp = std::make_shared<lldb_private::Type>(
+      type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(), ar.Size,
+      nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl,
+      array_ct, lldb_private::Type::eResolveStateFull);
+  array_sp->SetEncodingType(element_type.get());
+  return array_sp;
+}
+
 TypeSP SymbolFileNativePDB::CreateType(PdbSymUid type_uid) {
   const PdbTypeSymId &tsid = type_uid.asTypeSym();
   TypeIndex index(tsid.index);
@@ -816,6 +833,12 @@
     return CreateTagType(type_uid, ur);
   }
 
+  if (cvt.kind() == LF_ARRAY) {
+    ArrayRecord ar;
+    llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar));
+    return CreateArrayType(type_uid, ar);
+  }
+
   return nullptr;
 }
 
@@ -1441,6 +1464,25 @@
   auto types_iter = m_types.find(uid.toOpaqueId());
   lldbassert(types_iter != m_types.end());
 
+  if (cvt.kind() == LF_MODIFIER) {
+    TypeIndex unmodified_type = LookThroughModifierRecord(cvt);
+    cvt = m_index->tpi().getType(unmodified_type);
+    // LF_MODIFIERS usually point to forward decls, so this is the one case
+    // where we won't have been able to resolve a forward decl to a full decl
+    // earlier on.  So we need to do that now.
+    if (IsForwardRefUdt(cvt)) {
+      llvm::Expected<TypeIndex> expected_full_ti =
+          m_index->tpi().findFullDeclForForwardRef(unmodified_type);
+      if (!expected_full_ti) {
+        llvm::consumeError(expected_full_ti.takeError());
+        return false;
+      }
+      cvt = m_index->tpi().getType(*expected_full_ti);
+      lldbassert(!IsForwardRefUdt(cvt));
+      unmodified_type = *expected_full_ti;
+    }
+    uid = PdbSymUid::makeTypeSymId(uid.tag(), unmodified_type, false);
+  }
   TypeIndex field_list_ti = GetFieldListIndex(cvt);
   CVType field_list_cvt = m_index->tpi().getType(field_list_ti);
   if (field_list_cvt.kind() != LF_FIELDLIST)
Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
+++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -59,6 +59,8 @@
 
 lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access);
 llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt);
+llvm::codeview::TypeIndex
+LookThroughModifierRecord(llvm::codeview::CVType modifier);
 
 llvm::StringRef DropNameScope(llvm::StringRef name);
 
Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -343,6 +343,13 @@
   }
 }
 
+TypeIndex lldb_private::npdb::LookThroughModifierRecord(CVType modifier) {
+  lldbassert(modifier.kind() == LF_MODIFIER);
+  ModifierRecord mr;
+  llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(modifier, mr));
+  return mr.ModifiedType;
+}
+
 llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) {
   // Not all PDB names can be parsed with CPlusPlusNameParser.
   // E.g. it fails on names containing `anonymous namespace'.
Index: lldb/lit/SymbolFile/NativePDB/global-classes.cpp
===================================================================
--- /dev/null
+++ lldb/lit/SymbolFile/NativePDB/global-classes.cpp
@@ -0,0 +1,275 @@
+// clang-format off
+// REQUIRES: lld
+
+// Test that we can display tag types.
+// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
+// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \
+// RUN:     %p/Inputs/globals-classes.lldbinit | FileCheck %s
+
+enum class EnumType : unsigned {
+  A = 1,
+  B = 2
+};
+
+class ClassNoPadding {
+  /* [ 0] */ unsigned char a = 86;
+  /* [ 1] */ char b = 'a';
+  /* [ 2] */ bool c = false;
+  /* [ 3] */ bool d = true;
+  /* [ 4] */ short e = -1234;
+  /* [ 6] */ unsigned short f = 8123;
+  /* [ 8] */ unsigned int g = 123908;
+  /* [12] */ int h = -890234;
+  /* [16] */ unsigned long i = 2908234;
+  /* [20] */ long j = 7234890;
+  /* [24] */ float k = 908234.12392;
+  /* [28] */ EnumType l = EnumType::A;
+  /* [32] */ double m = 23890.897423;
+  /* [40] */ unsigned long long n = 23490782;
+  /* [48] */ long long o = -923409823;
+  /* [56] */ int p[5] = { 2, 3, 5, 8, 13 };
+};
+
+class ClassWithPadding {
+  /* [ 0] */ char a = '0';
+  //         char padding[1];
+  /* [ 2] */ short b = 50;
+  /* [ 4] */ char c[2] = { '0', '1' };
+  //         char padding[2];
+  /* [ 8] */ int d = 100;
+  /* [12] */ char e = '0';
+  //         char padding[3];
+  /* [16] */ int f = 200;
+  //         char padding[4];
+  /* [24] */ long long g = 300;
+  /* [32] */ char h[3] = { '0', '1', '2' };
+  //         char padding[5];
+  /* [40] */ long long i = 400;
+  /* [48] */ char j[2] = { '0', '1' };
+  //         char padding[6];
+  /* [56] */ long long k = 500;
+  /* [64] */ char l = '0';
+  //         char padding[7];
+  /* [72] */ long long m = 600;
+} ;
+
+struct EmptyBase {};
+
+template<typename T>
+struct BaseClass {
+  constexpr BaseClass(int N)
+    : BaseMember(N) {}
+
+  int BaseMember;
+};
+
+struct DerivedClass : public BaseClass<int> {
+  constexpr DerivedClass(int Base, int Derived)
+    : BaseClass(Base), DerivedMember(Derived) {}
+
+  int DerivedMember;
+};
+
+struct EBO : public EmptyBase {
+  constexpr EBO(int N) : Member(N) {}
+  int Member;
+};
+
+struct PaddedBases : public BaseClass<char>, public BaseClass<short>, BaseClass<int> {
+  constexpr PaddedBases(char CH, short S, int N, long long D)
+    : BaseClass<char>(CH), BaseClass<short>(S), BaseClass<int>(N), DerivedMember(D) {}
+  long long DerivedMember;
+};
+
+struct Statics {
+  static char a;
+  static bool b;
+  static short c;
+  static unsigned short d;
+  static unsigned int e;
+  static int f;
+  static unsigned long g;
+  static long h;
+  static float i;
+  static EnumType j;
+  static double k;
+  static unsigned long long l;
+  static long long m;
+};
+
+char Statics::a = 'a';
+bool Statics::b = true;
+short Statics::c = 1234;
+unsigned short Statics::d = 2345;
+unsigned int Statics::e = 3456;
+int Statics::f = 4567;
+unsigned long Statics::g = 5678;
+long Statics::h = 6789;
+float Statics::i = 7890.1234;
+EnumType Statics::j = EnumType::A;
+double Statics::k = 8901.2345;
+unsigned long long Statics::l = 9012345;
+long long Statics::m = 1234567;
+
+
+struct Pointers {
+  void *a = nullptr;
+  char *b = &Statics::a;
+  bool *c = &Statics::b;
+  short *e = &Statics::c;
+  unsigned short *f = &Statics::d;
+  unsigned int *g = &Statics::e;
+  int *h = &Statics::f;
+  unsigned long *i = &Statics::g;
+  long *j = &Statics::h;
+  float *k = &Statics::i;
+  EnumType *l = &Statics::j;
+  double *m = &Statics::k;
+  unsigned long long *n = &Statics::l;
+  long long *o = &Statics::m;
+};
+
+struct References {
+  char &a = Statics::a;
+  bool &b = Statics::b;
+  short &c = Statics::c;
+  unsigned short &d = Statics::d;
+  unsigned int &e = Statics::e;
+  int &f = Statics::f;
+  unsigned long &g = Statics::g;
+  long &h = Statics::h;
+  float &i = Statics::i;
+  EnumType &j = Statics::j;
+  double &k = Statics::k;
+  unsigned long long &l = Statics::l;
+  long long &m = Statics::m;
+};
+
+
+constexpr ClassWithPadding ClassWithPaddingInstance;
+// CHECK:      (lldb) target variable -T ClassWithPaddingInstance
+// CHECK-NEXT: (const ClassWithPadding) ClassWithPaddingInstance = {
+// CHECK-NEXT:   (char) a = '0'
+// CHECK-NEXT:   (short) b = 50
+// CHECK-NEXT:   (char [2]) c = "01"
+// CHECK-NEXT:   (int) d = 100
+// CHECK-NEXT:   (char) e = '0'
+// CHECK-NEXT:   (int) f = 200
+// CHECK-NEXT:   (long long) g = 300
+// CHECK-NEXT:   (char [3]) h = "012"
+// CHECK-NEXT:   (long long) i = 400
+// CHECK-NEXT:   (char [2]) j = "01"
+// CHECK-NEXT:   (long long) k = 500
+// CHECK-NEXT:   (char) l = '0'
+// CHECK-NEXT:   (long long) m = 600
+// CHECK-NEXT: }
+
+constexpr ClassNoPadding ClassNoPaddingInstance;
+// CHECK:      (lldb) target variable -T ClassNoPaddingInstance
+// CHECK-NEXT: (const ClassNoPadding) ClassNoPaddingInstance = {
+// CHECK-NEXT:   (unsigned char) a = 'V'
+// CHECK-NEXT:   (char) b = 'a'
+// CHECK-NEXT:   (bool) c = false
+// CHECK-NEXT:   (bool) d = true
+// CHECK-NEXT:   (short) e = -1234
+// CHECK-NEXT:   (unsigned short) f = 8123
+// CHECK-NEXT:   (unsigned int) g = 123908
+// CHECK-NEXT:   (int) h = -890234
+// CHECK-NEXT:   (unsigned long) i = 2908234
+// CHECK-NEXT:   (long) j = 7234890
+// CHECK-NEXT:   (float) k = 908234.125
+// CHECK-NEXT:   (EnumType) l = A
+// CHECK-NEXT:   (double) m = 23890.897422999999
+// CHECK-NEXT:   (unsigned long long) n = 23490782
+// CHECK-NEXT:     (long long) o = -923409823
+// CHECK-NEXT:     (int [5]) p = {
+// CHECK-NEXT:       (int) [0] = 2
+// CHECK-NEXT:       (int) [1] = 3
+// CHECK-NEXT:       (int) [2] = 5
+// CHECK-NEXT:       (int) [3] = 8
+// CHECK-NEXT:       (int) [4] = 13
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+
+constexpr DerivedClass DC(10, 20);
+// CHECK:      (lldb) target variable -T DC
+// CHECK-NEXT: (const DerivedClass) DC = {
+// CHECK-NEXT:   (BaseClass<int>) BaseClass<int> = {
+// CHECK-NEXT:     (int) BaseMember = 10
+// CHECK-NEXT:   }
+// CHECK-NEXT:   (int) DerivedMember = 20
+// CHECK-NEXT: }
+
+constexpr EBO EBOC(20);
+// CHECK:      (lldb) target variable -T EBOC
+// CHECK-NEXT: (const EBO) EBOC = {
+// CHECK-NEXT:   (int) Member = 20
+// CHECK-NEXT: }
+
+constexpr PaddedBases PBC('a', 12, 120, 1200);
+// CHECK:      (lldb) target variable -T PBC
+// CHECK-NEXT: (const PaddedBases) PBC = {
+// CHECK-NEXT:   (BaseClass<char>) BaseClass<char> = {
+// CHECK-NEXT:     (int) BaseMember = 97
+// CHECK-NEXT:   }
+// CHECK-NEXT:   (BaseClass<short>) BaseClass<short> = {
+// CHECK-NEXT:     (int) BaseMember = 12
+// CHECK-NEXT:   }
+// CHECK-NEXT:   (BaseClass<int>) BaseClass<int> = {
+// CHECK-NEXT:     (int) BaseMember = 120
+// CHECK-NEXT:   }
+// CHECK-NEXT:   (long long) DerivedMember = 1200
+// CHECK-NEXT: }
+
+constexpr struct {
+  int x = 12;
+  EBO EBOC{ 42 };
+} UnnamedClassInstance;
+// CHECK:      (lldb) target variable -T UnnamedClassInstance
+// CHECK-NEXT: (const <unnamed-type-UnnamedClassInstance>) UnnamedClassInstance = {
+// CHECK-NEXT:   (int) x = 12
+// CHECK-NEXT:   (EBO) EBOC = {
+// CHECK-NEXT:     (int) Member = 42
+// CHECK-NEXT:   }
+// CHECK-NEXT: }
+
+constexpr Pointers PointersInstance;
+// CHECK:      (lldb) target variable -T PointersInstance
+// CHECK-NEXT: (const Pointers) PointersInstance = {
+// CHECK-NEXT:   (void *) a = {{.*}}
+// CHECK-NEXT:   (char *) b = {{.*}}
+// CHECK-NEXT:   (bool *) c = {{.*}}
+// CHECK-NEXT:   (short *) e = {{.*}}
+// CHECK-NEXT:   (unsigned short *) f = {{.*}}
+// CHECK-NEXT:   (unsigned int *) g = {{.*}}
+// CHECK-NEXT:   (int *) h = {{.*}}
+// CHECK-NEXT:   (unsigned long *) i = {{.*}}
+// CHECK-NEXT:   (long *) j = {{.*}}
+// CHECK-NEXT:   (float *) k = {{.*}}
+// CHECK-NEXT:   (EnumType *) l = {{.*}}
+// CHECK-NEXT:   (double *) m = {{.*}}
+// CHECK-NEXT:   (unsigned long long *) n = {{.*}}
+// CHECK-NEXT:   (long long *) o = {{.*}}
+// CHECK-NEXT: }
+constexpr References ReferencesInstance;
+// CHECK:      (lldb) target variable -T ReferencesInstance
+// CHECK-NEXT: (const References) ReferencesInstance = {
+// CHECK-NEXT:   (char &) a = {{.*}}
+// CHECK-NEXT:   (bool &) b = {{.*}}
+// CHECK-NEXT:   (short &) c = {{.*}}
+// CHECK-NEXT:   (unsigned short &) d = {{.*}}
+// CHECK-NEXT:   (unsigned int &) e = {{.*}}
+// CHECK-NEXT:   (int &) f = {{.*}}
+// CHECK-NEXT:   (unsigned long &) g = {{.*}}
+// CHECK-NEXT:   (long &) h = {{.*}}
+// CHECK-NEXT:   (float &) i = {{.*}}
+// CHECK-NEXT:   (EnumType &) j = {{.*}}
+// CHECK-NEXT:   (double &) k = {{.*}}
+// CHECK-NEXT:   (unsigned long long &) l = {{.*}}
+// CHECK-NEXT:   (long long &) m = {{.*}}
+// CHECK-NEXT: }
+
+int main(int argc, char **argv) {
+  return 0;
+}
\ No newline at end of file
Index: lldb/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
===================================================================
--- /dev/null
+++ lldb/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
@@ -0,0 +1,14 @@
+settings set auto-one-line-summaries false
+
+target variable -T ClassWithPaddingInstance
+target variable -T ClassNoPaddingInstance
+target variable -T DC
+target variable -T EBOC
+target variable -T PBC
+
+target variable -T UnnamedClassInstance
+
+target variable -T PointersInstance
+target variable -T ReferencesInstance
+
+quit
\ No newline at end of file
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D... Zachary Turner via Phabricator via lldb-commits

Reply via email to