[Lldb-commits] [lldb] r346429 - [NativePDB] Higher fidelity reconstruction of AST from Debug Info.

Zachary Turner via lldb-commits lldb-commits at lists.llvm.org
Thu Nov 8 10:50:11 PST 2018


Author: zturner
Date: Thu Nov  8 10:50:11 2018
New Revision: 346429

URL: http://llvm.org/viewvc/llvm-project?rev=346429&view=rev
Log:
[NativePDB] Higher fidelity reconstruction of AST from Debug Info.

In order to accurately put a type into the correct location in the AST
we construct from debug info, we need to be able to determine what
DeclContext (namespace, global, nested class, etc) that it goes into.
PDB doesn't contain this mapping.  It does, however, contain the reverse
mapping.  That is, for a given class type T, you can determine all
classes Q1, Q2, ..., Qn that are nested inside of T.  We need to know,
for a given class type Q, what type T is it nested inside of.

This patch builds this map as a pre-processing step when we first
load the PDB by scanning every type.  Initial tests show that while
this can be slow in debug builds of LLDB, it is quite fast in release
builds (less than 2 seconds for a ~1GB PDB, and it only needs to happen
once).

Furthermore, having this pre-processing step in place allows us to
repurpose it for building up other kinds of indexing to it down the
line.  For the time being, this gives us very accurate reconstruction
of the DeclContext hierarchy.

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

Added:
    lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
    lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
Modified:
    lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
    lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
    lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
    lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h

Added: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit?rev=346429&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/ast-reconstruction.lldbinit Thu Nov  8 10:50:11 2018
@@ -0,0 +1,20 @@
+target variable TC
+target variable TS
+target variable TU
+target variable TE
+
+target variable ABCInt
+target variable ABCFloat
+target variable ABCVoid
+
+target variable AC0
+target variable ACNeg1
+
+target variable AC0D
+target variable ACNeg1D
+target variable AD
+target variable ADE
+
+target modules dump ast
+
+quit

Modified: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit (original)
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit Thu Nov  8 10:50:11 2018
@@ -9,4 +9,6 @@ target variable h
 target variable i
 target variable incomplete
 
+target modules dump ast
+
 quit

Modified: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit (original)
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/globals-classes.lldbinit Thu Nov  8 10:50:11 2018
@@ -11,4 +11,6 @@ target variable -T UnnamedClassInstance
 target variable -T PointersInstance
 target variable -T ReferencesInstance
 
+target modules dump ast
+
 quit
\ No newline at end of file

Added: lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp?rev=346429&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/ast-reconstruction.cpp Thu Nov  8 10:50:11 2018
@@ -0,0 +1,131 @@
+// clang-format off
+// REQUIRES: lld
+
+// Test various interesting cases for AST reconstruction.
+// RUN: clang-cl /Z7 /GS- /GR- /c /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/ast-reconstruction.lldbinit 2>&1 | FileCheck %s
+
+// Test trivial versions of each tag type.
+class TrivialC {};
+struct TrivialS {};
+union TrivialU {};
+enum TrivialE {TE_A};
+
+// Test reconstruction of DeclContext hierarchies.
+namespace A {
+  namespace B {
+    template<typename T>
+    struct C {
+      T ABCMember;
+    };
+
+    // Let's try a template specialization with a different implementation
+    template<>
+    struct C<void> {
+      void *ABCSpecializationMember;
+    };
+  }
+
+  // Let's make sure we can distinguish classes and namespaces.  Also let's try
+  // a non-type template parameter.
+  template<int N>
+  struct C {
+    class D {
+      int ACDMember = 0;
+      C<N - 1> *CPtr = nullptr;
+    };
+  };
+
+  struct D {
+    // Let's make a nested class with the same name as another nested class
+    // elsewhere, and confirm that they appear in the right DeclContexts in
+    // the AST.
+    struct E {
+      int ADDMember;
+    };
+  };
+}
+
+
+// Let's try an anonymous namespace.
+namespace {
+  template<typename T>
+  struct Anonymous {
+    int AnonymousMember;
+    // And a nested class within an anonymous namespace
+    struct D {
+      int AnonymousDMember;
+    };
+  };
+}
+
+TrivialC TC;
+TrivialS TS;
+TrivialU TU;
+TrivialE TE;
+
+A::B::C<int> ABCInt;
+A::B::C<float> ABCFloat;
+A::B::C<void> ABCVoid;
+
+A::C<0> AC0;
+A::C<-1> ACNeg1;
+
+A::C<0>::D AC0D;
+A::C<-1>::D ACNeg1D;
+A::D AD;
+A::D::E ADE;
+
+// FIXME: Anonymous namespaces aren't working correctly.
+Anonymous<int> AnonInt;
+Anonymous<A::B::C<void>> AnonABCVoid;
+Anonymous<A::B::C<int>>::D AnonABCVoidD;
+
+// FIXME: Enum size isn't being correctly determined.
+// FIXME: Can't read memory for variable values.
+
+// CHECK: (TrivialC) TC = {}
+// CHECK: (TrivialS) TS = {}
+// CHECK: (TrivialU) TU = {}
+// CHECK: (TrivialE) TE = <Unable to determine byte size.>
+// CHECK: (A::B::C<int>) ABCInt = (ABCMember = <read memory from {{.*}} failed>)
+// CHECK: (A::B::C<float>) ABCFloat = (ABCMember = <read memory from {{.*}} failed>)
+// CHECK: (A::B::C<void>) ABCVoid = (ABCSpecializationMember = <read memory from {{.*}} failed>)
+// CHECK: (A::C<0>) AC0 = {}
+// CHECK: (A::C<-1>) ACNeg1 = {}
+// CHECK: (A::C<0>::D) AC0D = (ACDMember = <read memory from {{.*}} failed>, CPtr = <read memory from {{.*}} failed>)
+// CHECK: (A::C<-1>::D) ACNeg1D = (ACDMember = <read memory from {{.*}} failed>, CPtr = <read memory from {{.*}} failed>)
+// CHECK: (A::D) AD = {}
+// CHECK: (A::D::E) ADE = (ADDMember = <read memory from {{.*}} failed>)
+// CHECK: Dumping clang ast for 1 modules.
+// CHECK: TranslationUnitDecl {{.*}}
+// CHECK: |-CXXRecordDecl {{.*}} class TrivialC definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TrivialS definition
+// CHECK: |-CXXRecordDecl {{.*}} union TrivialU definition
+// CHECK: |-EnumDecl {{.*}} TrivialE
+// CHECK: |-NamespaceDecl {{.*}} A
+// CHECK: | |-NamespaceDecl {{.*}} B
+// CHECK: | | |-CXXRecordDecl {{.*}} struct C<int> definition
+// CHECK: | | | `-FieldDecl {{.*}} ABCMember 'int'
+// CHECK: | | |-CXXRecordDecl {{.*}} struct C<float> definition
+// CHECK: | | | `-FieldDecl {{.*}} ABCMember 'float'
+// CHECK: | | `-CXXRecordDecl {{.*}} struct C<void> definition
+// CHECK: | |   `-FieldDecl {{.*}} ABCSpecializationMember 'void *'
+// CHECK: | |-CXXRecordDecl {{.*}} struct C<0> definition
+// CHECK: | | `-CXXRecordDecl {{.*}} class D definition
+// CHECK: | |   |-FieldDecl {{.*}} ACDMember 'int'
+// CHECK: | |   `-FieldDecl {{.*}} CPtr 'A::C<-1> *'
+// CHECK: | |-CXXRecordDecl {{.*}} struct C<-1> definition
+// CHECK: | | `-CXXRecordDecl {{.*}} class D definition
+// CHECK: | |   |-FieldDecl {{.*}} ACDMember 'int'
+// CHECK: | |   `-FieldDecl {{.*}} CPtr 'A::C<-2> *'
+// CHECK: | |-CXXRecordDecl {{.*}} struct C<-2>
+// CHECK: | `-CXXRecordDecl {{.*}} struct D definition
+// CHECK: |   `-CXXRecordDecl {{.*}} struct E definition
+// CHECK: |     `-FieldDecl {{.*}} ADDMember 'int'
+
+int main(int argc, char **argv) {
+  return 0;
+}
\ No newline at end of file

Modified: lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp (original)
+++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp Thu Nov  8 10:50:11 2018
@@ -2,7 +2,7 @@
 // REQUIRES: lld
 
 // Test that we can display function signatures with class types.
-// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s
+// RUN: clang-cl /Z7 /GS- /GR- /c -fstandalone-debug -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/function-types-classes.lldbinit | FileCheck %s
@@ -66,6 +66,13 @@ struct B {
   };
 };
 
+// clang (incorrectly) doesn't emit debug information for outer classes
+// unless they are instantiated.  They should also be emitted if there
+// is an inner class which is instantiated.
+A::C ForceInstantiateAC;
+B ForceInstantiateB;
+B::A ForceInstantiateBA;
+
 template<typename T>
 struct TC {};
 
@@ -81,31 +88,19 @@ auto d = &four<C, const volatile U*, con
 
 // classes nested in namespaces and inner classes
 
-// FIXME: LLDB with native pdb plugin doesn't currently resolve nested names
-// correctly, because it requires creating clang::NamespaceDecl or
-// clang::RecordDecl for the outer namespace or classes.  PDB doesn't contain
-// sufficient information to distinguish namespace scopes from nested class
-// scopes, so the best we can hope for is a heuristic reconstruction of the
-// clang AST based on demangling the type's unique name.  However, this is
-// as-yet unimplemented in the native PDB plugin, so for now all of these will
-// all just look like `S` when LLDB prints them.
 auto e = &three<A::B::S*, B::A::S*, A::C::S&>;
-// CHECK: (S *(*)(S *, S &)) e = {{.*}}
+// CHECK: (A::B::S *(*)(B::A::S *, A::C::S &)) e = {{.*}}
 auto f = &three<A::C::S&, A::B::S*, B::A::S*>;
-// CHECK: (S &(*)(S *, S *)) f = {{.*}}
+// CHECK: (A::C::S &(*)(A::B::S *, B::A::S *)) f = {{.*}}
 auto g = &three<B::A::S*, A::C::S&, A::B::S*>;
-// CHECK: (S *(*)(S &, S *)) g = {{.*}}
+// CHECK: (B::A::S *(*)(A::C::S &, A::B::S *)) g = {{.*}}
 
 // parameter types that are themselves template instantiations.
 auto h = &four<TC<void>, TC<int>, TC<TC<int>>, TC<A::B::S>>;
-// Note the awkward space in TC<TC<int> >.  This is because this is how template
-// instantiations are emitted by the compiler, as the fully instantiated name.
-// Only via reconstruction of the AST through the mangled type name (see above
-// comment) can we hope to do better than this).
-// CHECK: (TC<void> (*)(TC<int>, TC<TC<int> >, S>)) h = {{.*}}
+// CHECK: (TC<void> (*)(TC<int>, TC<struct TC<int>>, TC<struct A::B::S>)) h = {{.*}}
 
 auto i = &nullary<A::B::S>;
-// CHECK: (S (*)()) i = {{.*}}
+// CHECK: (A::B::S (*)()) i = {{.*}}
 
 
 // Make sure we can handle types that don't have complete debug info.
@@ -113,6 +108,25 @@ struct Incomplete;
 auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>;
 // CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}}
 
+// CHECK: TranslationUnitDecl {{.*}}
+// CHECK: |-CXXRecordDecl {{.*}} class C definition
+// CHECK: |-CXXRecordDecl {{.*}} union U definition
+// CHECK: |-EnumDecl {{.*}} E
+// CHECK: |-CXXRecordDecl {{.*}} struct S definition
+// CHECK: |-CXXRecordDecl {{.*}} struct B
+// CHECK: | |-CXXRecordDecl {{.*}} struct A
+// CHECK: | | |-CXXRecordDecl {{.*}} struct S
+// CHECK: |-NamespaceDecl {{.*}} A
+// CHECK: | |-CXXRecordDecl {{.*}} struct C
+// CHECK: | | |-CXXRecordDecl {{.*}} struct S
+// CHECK: | `-NamespaceDecl {{.*}} B
+// CHECK: |   `-CXXRecordDecl {{.*}} struct S definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<int> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct TC<int>> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct A::B::S> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct TC<void> definition
+// CHECK: |-CXXRecordDecl {{.*}} struct Incomplete
+
 int main(int argc, char **argv) {
   return 0;
 }

Modified: lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp (original)
+++ lldb/trunk/lit/SymbolFile/NativePDB/global-classes.cpp Thu Nov  8 10:50:11 2018
@@ -270,6 +270,94 @@ constexpr References ReferencesInstance;
 // CHECK-NEXT:   (long long &) m = {{.*}}
 // CHECK-NEXT: }
 
+// CHECK: Dumping clang ast for 1 modules.
+// CHECK: TranslationUnitDecl {{.*}}
+// CHECK: |-CXXRecordDecl {{.*}} class ClassWithPadding definition
+// CHECK: | |-FieldDecl {{.*}} a 'char'
+// CHECK: | |-FieldDecl {{.*}} b 'short'
+// CHECK: | |-FieldDecl {{.*}} c 'char [2]'
+// CHECK: | |-FieldDecl {{.*}} d 'int'
+// CHECK: | |-FieldDecl {{.*}} e 'char'
+// CHECK: | |-FieldDecl {{.*}} f 'int'
+// CHECK: | |-FieldDecl {{.*}} g 'long long'
+// CHECK: | |-FieldDecl {{.*}} h 'char [3]'
+// CHECK: | |-FieldDecl {{.*}} i 'long long'
+// CHECK: | |-FieldDecl {{.*}} j 'char [2]'
+// CHECK: | |-FieldDecl {{.*}} k 'long long'
+// CHECK: | |-FieldDecl {{.*}} l 'char'
+// CHECK: | `-FieldDecl {{.*}} m 'long long'
+// CHECK: |-CXXRecordDecl {{.*}} class ClassNoPadding definition
+// CHECK: | |-FieldDecl {{.*}} a 'unsigned char'
+// CHECK: | |-FieldDecl {{.*}} b 'char'
+// CHECK: | |-FieldDecl {{.*}} c 'bool'
+// CHECK: | |-FieldDecl {{.*}} d 'bool'
+// CHECK: | |-FieldDecl {{.*}} e 'short'
+// CHECK: | |-FieldDecl {{.*}} f 'unsigned short'
+// CHECK: | |-FieldDecl {{.*}} g 'unsigned int'
+// CHECK: | |-FieldDecl {{.*}} h 'int'
+// CHECK: | |-FieldDecl {{.*}} i 'unsigned long'
+// CHECK: | |-FieldDecl {{.*}} j 'long'
+// CHECK: | |-FieldDecl {{.*}} k 'float'
+// CHECK: | |-FieldDecl {{.*}} l 'EnumType'
+// CHECK: | |-FieldDecl {{.*}} m 'double'
+// CHECK: | |-FieldDecl {{.*}} n 'unsigned long long'
+// CHECK: | |-FieldDecl {{.*}} o 'long long'
+// CHECK: | `-FieldDecl {{.*}} p 'int [5]'
+// CHECK: |-EnumDecl {{.*}} EnumType
+// CHECK: | |-EnumConstantDecl {{.*}} A 'unsigned int'
+// CHECK: | `-EnumConstantDecl {{.*}} B 'unsigned int'
+// CHECK: |-CXXRecordDecl {{.*}} struct DerivedClass definition
+// CHECK: | |-public 'BaseClass<int>'
+// CHECK: | `-FieldDecl {{.*}} DerivedMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<int> definition
+// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct EBO definition
+// CHECK: | |-public 'EmptyBase'
+// CHECK: | `-FieldDecl {{.*}} Member 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct EmptyBase definition
+// CHECK: |-CXXRecordDecl {{.*}} struct PaddedBases definition
+// CHECK: | |-public 'BaseClass<char>'
+// CHECK: | |-public 'BaseClass<short>'
+// CHECK: | |-public 'BaseClass<int>'
+// CHECK: | `-FieldDecl {{.*}} DerivedMember 'long long'
+// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<char> definition
+// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct BaseClass<short> definition
+// CHECK: | `-FieldDecl {{.*}} BaseMember 'int'
+// CHECK: |-CXXRecordDecl {{.*}} struct <unnamed-type-UnnamedClassInstance> definition
+// CHECK: | |-FieldDecl {{.*}} x 'int'
+// CHECK: | `-FieldDecl {{.*}} EBOC 'EBO'
+// CHECK: |-CXXRecordDecl {{.*}} struct Pointers definition
+// CHECK: | |-FieldDecl {{.*}} a 'void *'
+// CHECK: | |-FieldDecl {{.*}} b 'char *'
+// CHECK: | |-FieldDecl {{.*}} c 'bool *'
+// CHECK: | |-FieldDecl {{.*}} e 'short *'
+// CHECK: | |-FieldDecl {{.*}} f 'unsigned short *'
+// CHECK: | |-FieldDecl {{.*}} g 'unsigned int *'
+// CHECK: | |-FieldDecl {{.*}} h 'int *'
+// CHECK: | |-FieldDecl {{.*}} i 'unsigned long *'
+// CHECK: | |-FieldDecl {{.*}} j 'long *'
+// CHECK: | |-FieldDecl {{.*}} k 'float *'
+// CHECK: | |-FieldDecl {{.*}} l 'EnumType *'
+// CHECK: | |-FieldDecl {{.*}} m 'double *'
+// CHECK: | |-FieldDecl {{.*}} n 'unsigned long long *'
+// CHECK: | `-FieldDecl {{.*}} o 'long long *'
+// CHECK: |-CXXRecordDecl {{.*}} struct References definition
+// CHECK: | |-FieldDecl {{.*}} a 'char &'
+// CHECK: | |-FieldDecl {{.*}} b 'bool &'
+// CHECK: | |-FieldDecl {{.*}} c 'short &'
+// CHECK: | |-FieldDecl {{.*}} d 'unsigned short &'
+// CHECK: | |-FieldDecl {{.*}} e 'unsigned int &'
+// CHECK: | |-FieldDecl {{.*}} f 'int &'
+// CHECK: | |-FieldDecl {{.*}} g 'unsigned long &'
+// CHECK: | |-FieldDecl {{.*}} h 'long &'
+// CHECK: | |-FieldDecl {{.*}} i 'float &'
+// CHECK: | |-FieldDecl {{.*}} j 'EnumType &'
+// CHECK: | |-FieldDecl {{.*}} k 'double &'
+// CHECK: | |-FieldDecl {{.*}} l 'unsigned long long &'
+// CHECK: | `-FieldDecl {{.*}} m 'long long &'
+// CHECK: `-<undeserialized declarations>
+
 int main(int argc, char **argv) {
   return 0;
 }
\ No newline at end of file

Modified: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp Thu Nov  8 10:50:11 2018
@@ -21,6 +21,38 @@ using namespace lldb_private::npdb;
 using namespace llvm::codeview;
 using namespace llvm::pdb;
 
+CVTagRecord CVTagRecord::create(CVType type) {
+  assert(IsTagRecord(type) && "type is not a tag record!");
+  switch (type.kind()) {
+  case LF_CLASS:
+  case LF_STRUCTURE:
+  case LF_INTERFACE: {
+    ClassRecord cr;
+    llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr));
+    return CVTagRecord(std::move(cr));
+  }
+  case LF_UNION: {
+    UnionRecord ur;
+    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur));
+    return CVTagRecord(std::move(ur));
+  }
+  case LF_ENUM: {
+    EnumRecord er;
+    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er));
+    return CVTagRecord(std::move(er));
+  }
+  default:
+    llvm_unreachable("Unreachable!");
+  }
+}
+
+CVTagRecord::CVTagRecord(ClassRecord &&c)
+    : cvclass(std::move(c)),
+      m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {}
+CVTagRecord::CVTagRecord(UnionRecord &&u)
+    : cvunion(std::move(u)), m_kind(Union) {}
+CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {}
+
 PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) {
   switch (kind) {
   case S_COMPILE3:
@@ -94,6 +126,8 @@ PDB_SymType lldb_private::npdb::CVTypeTo
     return PDB_SymType::Enum;
   case LF_PROCEDURE:
     return PDB_SymType::FunctionSig;
+  case LF_BITFIELD:
+    return PDB_SymType::BuiltinType;
   default:
     lldbassert(false && "Invalid type record kind!");
   }
@@ -304,6 +338,18 @@ bool lldb_private::npdb::IsForwardRefUdt
   default:
     return false;
   }
+}
+
+bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) {
+  switch (cvt.kind()) {
+  case LF_CLASS:
+  case LF_STRUCTURE:
+  case LF_UNION:
+  case LF_ENUM:
+    return true;
+  default:
+    return false;
+  }
 }
 
 lldb::AccessType

Modified: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.h Thu Nov  8 10:50:11 2018
@@ -13,6 +13,7 @@
 #include "lldb/lldb-enumerations.h"
 
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 
 #include <tuple>
@@ -21,6 +22,48 @@
 namespace lldb_private {
 namespace npdb {
 
+struct CVTagRecord {
+  enum Kind { Class, Struct, Union, Enum };
+
+  static CVTagRecord create(llvm::codeview::CVType type);
+
+  Kind kind() const { return m_kind; }
+
+  const llvm::codeview::TagRecord &asTag() const {
+    if (m_kind == Struct || m_kind == Class)
+      return cvclass;
+    if (m_kind == Enum)
+      return cvenum;
+    return cvunion;
+  }
+
+  const llvm::codeview::ClassRecord &asClass() const {
+    assert(m_kind == Struct || m_kind == Class);
+    return cvclass;
+  }
+
+  const llvm::codeview::EnumRecord &asEnum() const {
+    assert(m_kind == Enum);
+    return cvenum;
+  }
+
+  const llvm::codeview::UnionRecord &asUnion() const {
+    assert(m_kind == Union);
+    return cvunion;
+  }
+
+private:
+  CVTagRecord(llvm::codeview::ClassRecord &&c);
+  CVTagRecord(llvm::codeview::UnionRecord &&u);
+  CVTagRecord(llvm::codeview::EnumRecord &&e);
+  Kind m_kind;
+  union {
+    llvm::codeview::ClassRecord cvclass;
+    llvm::codeview::EnumRecord cvenum;
+    llvm::codeview::UnionRecord cvunion;
+  };
+};
+
 struct SegmentOffset {
   SegmentOffset() = default;
   SegmentOffset(uint16_t s, uint32_t o) : segment(s), offset(o) {}
@@ -56,6 +99,7 @@ inline bool IsValidRecord(const llvm::co
 }
 
 bool IsForwardRefUdt(llvm::codeview::CVType cvt);
+bool IsTagRecord(llvm::codeview::CVType cvt);
 
 lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access);
 llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt);

Modified: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp Thu Nov  8 10:50:11 2018
@@ -13,13 +13,16 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
 
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/StreamBuffer.h"
+#include "lldb/Core/StreamFile.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/ClangASTImporter.h"
 #include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/ClangUtil.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/LineTable.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -43,14 +46,14 @@
 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Demangle/MicrosoftDemangle.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/Allocator.h"
 #include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/MemoryBuffer.h"
 
-#include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h"
-
 #include "PdbSymUid.h"
 #include "PdbUtil.h"
 #include "UdtRecordCompleter.h"
@@ -527,9 +530,60 @@ void SymbolFileNativePDB::InitializeObje
   TypeSystem *ts = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
   m_clang = llvm::dyn_cast_or_null<ClangASTContext>(ts);
   m_importer = llvm::make_unique<ClangASTImporter>();
+
+  PreprocessTpiStream();
   lldbassert(m_clang);
 }
 
+void SymbolFileNativePDB::PreprocessTpiStream() {
+  LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
+
+  for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) {
+    CVType type = types.getType(*ti);
+    if (!IsTagRecord(type))
+      continue;
+
+    CVTagRecord tag = CVTagRecord::create(type);
+    // We're looking for LF_NESTTYPE records in the field list, so ignore
+    // forward references (no field list), and anything without a nested class
+    // (since there won't be any LF_NESTTYPE records).
+    if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass())
+      continue;
+
+    struct ProcessTpiStream : public TypeVisitorCallbacks {
+      ProcessTpiStream(PdbIndex &index, TypeIndex parent,
+                       llvm::DenseMap<TypeIndex, TypeIndex> &parents)
+          : index(index), parents(parents), parent(parent) {}
+
+      PdbIndex &index;
+      llvm::DenseMap<TypeIndex, TypeIndex> &parents;
+      TypeIndex parent;
+
+      llvm::Error visitKnownMember(CVMemberRecord &CVR,
+                                   NestedTypeRecord &Record) override {
+        parents[Record.Type] = parent;
+        CVType child = index.tpi().getType(Record.Type);
+        if (!IsForwardRefUdt(child))
+          return llvm::ErrorSuccess();
+        llvm::Expected<TypeIndex> full_decl =
+            index.tpi().findFullDeclForForwardRef(Record.Type);
+        if (!full_decl) {
+          llvm::consumeError(full_decl.takeError());
+          return llvm::ErrorSuccess();
+        }
+        parents[*full_decl] = parent;
+        return llvm::ErrorSuccess();
+      }
+    };
+
+    CVType field_list = m_index->tpi().getType(tag.asTag().FieldList);
+    ProcessTpiStream process(*m_index, *ti, m_parent_types);
+    llvm::Error error = visitMemberRecordStream(field_list.data(), process);
+    if (error)
+      llvm::consumeError(std::move(error));
+  }
+}
+
 uint32_t SymbolFileNativePDB::GetNumCompileUnits() {
   const DbiModuleList &modules = m_index->dbi().modules();
   uint32_t count = modules.getModuleCount();
@@ -730,16 +784,69 @@ lldb::TypeSP SymbolFileNativePDB::Create
                                 ct, Type::eResolveStateFull);
 }
 
+static std::string RenderDemanglerNode(llvm::ms_demangle::Node *n) {
+  OutputStream OS;
+  initializeOutputStream(nullptr, nullptr, OS, 1024);
+  n->output(OS, llvm::ms_demangle::OF_Default);
+  OS << '\0';
+  return {OS.getBuffer()};
+}
+
+std::pair<clang::DeclContext *, std::string>
+SymbolFileNativePDB::CreateDeclInfoForType(const TagRecord &record,
+                                           TypeIndex ti) {
+  llvm::ms_demangle::Demangler demangler;
+  StringView sv(record.UniqueName.begin(), record.UniqueName.size());
+  llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv);
+  llvm::ms_demangle::IdentifierNode *idn =
+      ttn->QualifiedName->getUnqualifiedIdentifier();
+  std::string uname = RenderDemanglerNode(idn);
+
+  llvm::ms_demangle::NodeArrayNode *name_components =
+      ttn->QualifiedName->Components;
+  llvm::ArrayRef<llvm::ms_demangle::Node *> scopes(name_components->Nodes,
+                                                   name_components->Count - 1);
+
+  clang::DeclContext *context = m_clang->GetTranslationUnitDecl();
+
+  // If this type doesn't have a parent type in the debug info, then the best we
+  // can do is to say that it's either a series of namespaces (if the scope is
+  // non-empty), or the translation unit (if the scope is empty).
+  auto parent_iter = m_parent_types.find(ti);
+  if (parent_iter == m_parent_types.end()) {
+    if (scopes.empty())
+      return {context, uname};
+
+    for (llvm::ms_demangle::Node *scope : scopes) {
+      auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope);
+      std::string str = RenderDemanglerNode(nii);
+      context = m_clang->GetUniqueNamespaceDeclaration(str.c_str(), context);
+    }
+    return {context, uname};
+  }
+
+  // Otherwise, all we need to do is get the parent type of this type and
+  // recurse into our lazy type creation / AST reconstruction logic to get an
+  // LLDB TypeSP for the parent.  This will cause the AST to automatically get
+  // the right DeclContext created for any parent.
+  TypeSP parent = GetOrCreateType(parent_iter->second);
+  if (!parent)
+    return {context, uname};
+  CompilerType parent_ct = parent->GetForwardCompilerType();
+  clang::QualType qt = ClangUtil::GetCanonicalQualType(parent_ct);
+  context = clang::TagDecl::castToDeclContext(qt->getAsTagDecl());
+  return {context, uname};
+}
+
 lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion(
-    PdbSymUid type_uid, llvm::StringRef name, size_t size,
+    PdbSymUid type_uid, const llvm::codeview::TagRecord &record, size_t size,
     clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) {
 
-  // Ignore unnamed-tag UDTs.
-  name = DropNameScope(name);
-  if (name.empty())
-    return nullptr;
-
-  clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl();
+  const PdbTypeSymId &tid = type_uid.asTypeSym();
+  TypeIndex ti(tid.index);
+  clang::DeclContext *decl_context = nullptr;
+  std::string uname;
+  std::tie(decl_context, uname) = CreateDeclInfoForType(record, ti);
 
   lldb::AccessType access =
       (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic;
@@ -749,8 +856,9 @@ lldb::TypeSP SymbolFileNativePDB::Create
   metadata.SetIsDynamicCXXType(false);
 
   CompilerType ct =
-      m_clang->CreateRecordType(decl_context, access, name.str().c_str(), ttk,
+      m_clang->CreateRecordType(decl_context, access, uname.c_str(), ttk,
                                 lldb::eLanguageTypeC_plus_plus, &metadata);
+
   lldbassert(ct.IsValid());
 
   clang::CXXRecordDecl *record_decl =
@@ -771,7 +879,7 @@ lldb::TypeSP SymbolFileNativePDB::Create
   // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE.
   Declaration decl;
   return std::make_shared<Type>(type_uid.toOpaqueId(), m_clang->GetSymbolFile(),
-                                ConstString(name), size, nullptr,
+                                ConstString(uname), size, nullptr,
                                 LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
                                 ct, Type::eResolveStateForward);
 }
@@ -782,14 +890,13 @@ lldb::TypeSP SymbolFileNativePDB::Create
 
   clang::MSInheritanceAttr::Spelling inheritance =
       GetMSInheritance(m_index->tpi().typeCollection(), cr);
-  return CreateClassStructUnion(type_uid, cr.getName(), cr.getSize(), ttk,
-                                inheritance);
+  return CreateClassStructUnion(type_uid, cr, cr.getSize(), ttk, inheritance);
 }
 
 lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid,
                                                 const UnionRecord &ur) {
   return CreateClassStructUnion(
-      type_uid, ur.getName(), ur.getSize(), clang::TTK_Union,
+      type_uid, ur, ur.getSize(), clang::TTK_Union,
       clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance);
 }
 

Modified: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h?rev=346429&r1=346428&r2=346429&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h Thu Nov  8 10:50:11 2018
@@ -162,6 +162,11 @@ public:
   void DumpClangAST(Stream &s) override;
 
 private:
+  std::pair<clang::DeclContext *, std::string>
+  CreateDeclInfoForType(const llvm::codeview::TagRecord &record,
+                        llvm::codeview::TypeIndex ti);
+
+  void PreprocessTpiStream();
   size_t FindTypesByName(llvm::StringRef name, uint32_t max_matches,
                          TypeMap &types);
 
@@ -180,10 +185,9 @@ private:
                                const llvm::codeview::ArrayRecord &ar);
   lldb::TypeSP CreateProcedureType(PdbSymUid type_uid,
                                    const llvm::codeview::ProcedureRecord &pr);
-  lldb::TypeSP
-  CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size,
-                         clang::TagTypeKind ttk,
-                         clang::MSInheritanceAttr::Spelling inheritance);
+  lldb::TypeSP CreateClassStructUnion(
+      PdbSymUid type_uid, const llvm::codeview::TagRecord &record, size_t size,
+      clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance);
 
   lldb::FunctionSP GetOrCreateFunction(PdbSymUid func_uid,
                                        const SymbolContext &sc);
@@ -209,6 +213,8 @@ private:
   llvm::DenseMap<clang::TagDecl *, DeclStatus> m_decl_to_status;
 
   llvm::DenseMap<lldb::user_id_t, clang::TagDecl *> m_uid_to_decl;
+  llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex>
+      m_parent_types;
 
   llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_global_vars;
   llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;




More information about the lldb-commits mailing list