[Lldb-commits] [lldb] r345047 - [NativePDB] Add basic support for tag types to the native pdb plugin.

Zachary Turner via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 23 09:37:53 PDT 2018


Author: zturner
Date: Tue Oct 23 09:37:53 2018
New Revision: 345047

URL: http://llvm.org/viewvc/llvm-project?rev=345047&view=rev
Log:
[NativePDB] Add basic support for tag types to the native pdb plugin.

This adds support to LLDB for named types (class, struct, union, and
enum).  This is true cross platform support, and hits the PDB file
directly without a dependency on Windows.  Tests are added which
compile a program with certain interesting types and then use
load the target in LLDB and use "type lookup -- <TypeName>" to
dump the layout of the type in LLDB without a running process.

Currently only fields are parsed -- we do not parse methods.  Also
we don't deal with bitfields or virtual bases correctly.  Those
will make good followups.

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

Added:
    lldb/trunk/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
    lldb/trunk/lit/SymbolFile/NativePDB/tag-types.cpp
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
Modified:
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
    lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h

Added: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit?rev=345047&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit Tue Oct 23 09:37:53 2018
@@ -0,0 +1,8 @@
+type lookup -- Struct
+type lookup -- Class
+type lookup -- Union
+type lookup -- Derived
+type lookup -- Derived2
+type lookup -- EnumInt
+type lookup -- EnumShort
+type lookup -- InvalidType

Added: lldb/trunk/lit/SymbolFile/NativePDB/tag-types.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/SymbolFile/NativePDB/tag-types.cpp?rev=345047&view=auto
==============================================================================
--- lldb/trunk/lit/SymbolFile/NativePDB/tag-types.cpp (added)
+++ lldb/trunk/lit/SymbolFile/NativePDB/tag-types.cpp Tue Oct 23 09:37:53 2018
@@ -0,0 +1,236 @@
+// clang-format off
+// REQUIRES: lld
+
+// Test that we can display tag types.
+// 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/tag-types.lldbinit | FileCheck %s
+
+// Test struct
+struct Struct {
+  // Test builtin types, which are represented by special CodeView type indices.
+  bool                B;
+  char                C;
+  signed char         SC;
+  unsigned char       UC;
+  char16_t            C16;
+  char32_t            C32;
+  wchar_t             WC;
+  short               S;
+  unsigned short      US;
+  int                 I;
+  unsigned int        UI;
+  long                L;
+  unsigned long       UL;
+  long long           LL;
+  unsigned long long  ULL;
+  float               F;
+  double              D;
+  long double         LD;
+};
+
+// Test class
+class Class {
+public:
+  // Test pointers to builtin types, which are represented by different special
+  // CodeView type indices.
+  bool                *PB;
+  char                *PC;
+  signed char         *PSC;
+  unsigned char       *PUC;
+  char16_t            *PC16;
+  char32_t            *PC32;
+  wchar_t             *PWC;
+  short               *PS;
+  unsigned short      *PUS;
+  int                 *PI;
+  unsigned int        *PUI;
+  long                *PL;
+  unsigned long       *PUL;
+  long long           *PLL;
+  unsigned long long  *PULL;
+  float               *PF;
+  double              *PD;
+  long double         *PLD;
+};
+
+// Test union
+union Union {
+  // Test modified types.
+  const bool                *PB;
+  const char                *PC;
+  const signed char         *PSC;
+  const unsigned char       *PUC;
+  const char16_t            *PC16;
+  const char32_t            *PC32;
+  const wchar_t             *PWC;
+  const short               *PS;
+  const unsigned short      *PUS;
+  const int                 *PI;
+  const unsigned int        *PUI;
+  const long                *PL;
+  const unsigned long       *PUL;
+  const long long           *PLL;
+  const unsigned long long  *PULL;
+  const float               *PF;
+  const double              *PD;
+  const long double         *PLD;
+};
+
+struct OneMember {
+  int N = 0;
+};
+
+
+// Test single inheritance.
+class Derived : public Class {
+public:
+  explicit Derived()
+    : Reference(*this), RefMember(Member), RValueRefMember((OneMember&&)Member) {}
+
+  // Test reference to self, to make sure we don't end up in an
+  // infinite cycle.
+  Derived &Reference;
+
+  // Test aggregate class member.
+  OneMember Member;
+
+  // And modified aggregate class member.
+  const OneMember ConstMember;
+  volatile OneMember VolatileMember;
+  const volatile OneMember CVMember;
+
+  // And all types of pointers to class members
+  OneMember *PtrMember;
+  OneMember &RefMember;
+  OneMember &&RValueRefMember;
+};
+
+// Test multiple inheritance, as well as protected and private inheritance.
+class Derived2 : protected Class, private Struct {
+public:
+  // Test static data members
+  static unsigned StaticDataMember;
+};
+
+unsigned Derived2::StaticDataMember = 0;
+
+// Test scoped enums and unscoped enums.
+enum class EnumInt {
+  A = 1,
+  B = 2
+};
+
+// Test explicit underlying types
+enum EnumShort : short {
+  ES_A = 2,
+  ES_B = 3
+};
+
+int main(int argc, char **argv) {
+  Struct S;
+  Class C;
+  Union U;
+  Derived D;
+  Derived2 D2;
+  EnumInt EI;
+  EnumShort ES;
+  
+  return 0;
+}
+
+// CHECK:      (lldb) target create "{{.*}}tag-types.cpp.tmp.exe"
+// CHECK-NEXT: Current executable set to '{{.*}}tag-types.cpp.tmp.exe' (x86_64).
+// CHECK-NEXT: (lldb) command source -s 0 '{{.*}}tag-types.lldbinit'
+// CHECK-NEXT: Executing commands in '{{.*}}tag-types.lldbinit'.
+// CHECK-NEXT: (lldb) type lookup -- Struct
+// CHECK-NEXT: struct Struct {
+// CHECK-NEXT:     bool B;
+// CHECK-NEXT:     char C;
+// CHECK-NEXT:     signed char SC;
+// CHECK-NEXT:     unsigned char UC;
+// CHECK-NEXT:     char16_t C16;
+// CHECK-NEXT:     char32_t C32;
+// CHECK-NEXT:     wchar_t WC;
+// CHECK-NEXT:     short S;
+// CHECK-NEXT:     unsigned short US;
+// CHECK-NEXT:     int I;
+// CHECK-NEXT:     unsigned int UI;
+// CHECK-NEXT:     long L;
+// CHECK-NEXT:     unsigned long UL;
+// CHECK-NEXT:     long long LL;
+// CHECK-NEXT:     unsigned long long ULL;
+// CHECK-NEXT:     float F;
+// CHECK-NEXT:     double D;
+// CHECK-NEXT:     double LD;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Class
+// CHECK-NEXT: class Class {
+// CHECK-NEXT:     bool *PB;
+// CHECK-NEXT:     char *PC;
+// CHECK-NEXT:     signed char *PSC;
+// CHECK-NEXT:     unsigned char *PUC;
+// CHECK-NEXT:     char16_t *PC16;
+// CHECK-NEXT:     char32_t *PC32;
+// CHECK-NEXT:     wchar_t *PWC;
+// CHECK-NEXT:     short *PS;
+// CHECK-NEXT:     unsigned short *PUS;
+// CHECK-NEXT:     int *PI;
+// CHECK-NEXT:     unsigned int *PUI;
+// CHECK-NEXT:     long *PL;
+// CHECK-NEXT:     unsigned long *PUL;
+// CHECK-NEXT:     long long *PLL;
+// CHECK-NEXT:     unsigned long long *PULL;
+// CHECK-NEXT:     float *PF;
+// CHECK-NEXT:     double *PD;
+// CHECK-NEXT:     double *PLD;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Union
+// CHECK-NEXT: union Union {
+// CHECK-NEXT:     const bool *PB;
+// CHECK-NEXT:     const char *PC;
+// CHECK-NEXT:     const signed char *PSC;
+// CHECK-NEXT:     const unsigned char *PUC;
+// CHECK-NEXT:     const char16_t *PC16;
+// CHECK-NEXT:     const char32_t *PC32;
+// CHECK-NEXT:     const wchar_t *PWC;
+// CHECK-NEXT:     const short *PS;
+// CHECK-NEXT:     const unsigned short *PUS;
+// CHECK-NEXT:     const int *PI;
+// CHECK-NEXT:     const unsigned int *PUI;
+// CHECK-NEXT:     const long *PL;
+// CHECK-NEXT:     const unsigned long *PUL;
+// CHECK-NEXT:     const long long *PLL;
+// CHECK-NEXT:     const unsigned long long *PULL;
+// CHECK-NEXT:     const float *PF;
+// CHECK-NEXT:     const double *PD;
+// CHECK-NEXT:     const double *PLD;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Derived
+// CHECK-NEXT: class Derived : public Class {
+// CHECK-NEXT:     Derived &Reference;
+// CHECK-NEXT:     OneMember Member;
+// CHECK-NEXT:     const OneMember ConstMember;
+// CHECK-NEXT:     volatile OneMember VolatileMember;
+// CHECK-NEXT:     const volatile OneMember CVMember;
+// CHECK-NEXT:     OneMember *PtrMember;
+// CHECK-NEXT:     OneMember &RefMember;
+// CHECK-NEXT:     OneMember &&RValueRefMember;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- Derived2
+// CHECK-NEXT: class Derived2 : protected Class, private Struct {
+// CHECK-NEXT:     static unsigned int StaticDataMember;
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- EnumInt
+// CHECK-NEXT: enum EnumInt {
+// CHECK-NEXT:     A,
+// CHECK-NEXT:     B
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- EnumShort
+// CHECK-NEXT: enum EnumShort {
+// CHECK-NEXT:     ES_A,
+// CHECK-NEXT:     ES_B
+// CHECK-NEXT: }
+// CHECK-NEXT: (lldb) type lookup -- InvalidType
+// CHECK-NEXT: no type was found matching 'InvalidType'

Modified: lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt?rev=345047&r1=345046&r2=345047&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt Tue Oct 23 09:37:53 2018
@@ -3,6 +3,7 @@ add_lldb_library(lldbPluginSymbolFileNat
   PdbIndex.cpp
   PdbUtil.cpp
   SymbolFileNativePDB.cpp
+  UdtRecordCompleter.cpp
 
   LINK_LIBS
     clangAST

Modified: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp?rev=345047&r1=345046&r2=345047&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp Tue Oct 23 09:37:53 2018
@@ -17,6 +17,7 @@
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/Error.h"
 
@@ -51,6 +52,8 @@ PdbIndex::create(std::unique_ptr<llvm::p
   ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
   ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
 
+  result->m_tpi->buildHashMap();
+
   result->m_file = std::move(file);
 
   return std::move(result);
@@ -101,6 +104,9 @@ void PdbIndex::ParseSectionContribs() {
         : m_ctx(ctx), m_imap(imap) {}
 
     void visit(const SectionContrib &C) override {
+      if (C.Size == 0)
+        return;
+
       uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
       uint64_t end = va + C.Size;
       // IntervalMap's start and end represent a closed range, not a half-open

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=345047&r1=345046&r2=345047&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp Tue Oct 23 09:37:53 2018
@@ -9,8 +9,16 @@
 
 #include "SymbolFileNativePDB.h"
 
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+
 #include "lldb/Core/Module.h"
 #include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
 #include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/LineTable.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -18,15 +26,19 @@
 #include "lldb/Symbol/SymbolVendor.h"
 
 #include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
 #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
 #include "llvm/DebugInfo/CodeView/RecordName.h"
 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
 #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
 #include "llvm/Object/COFF.h"
 #include "llvm/Support/Allocator.h"
@@ -36,10 +48,11 @@
 
 #include "PdbSymUid.h"
 #include "PdbUtil.h"
+#include "UdtRecordCompleter.h"
 
 using namespace lldb;
 using namespace lldb_private;
-using namespace lldb_private::npdb;
+using namespace npdb;
 using namespace llvm::codeview;
 using namespace llvm::pdb;
 
@@ -139,6 +152,265 @@ static bool IsFunctionEpilogue(const Com
   return false;
 }
 
+static clang::MSInheritanceAttr::Spelling
+GetMSInheritance(LazyRandomTypeCollection &tpi, const ClassRecord &record) {
+  if (record.DerivationList == TypeIndex::None())
+    return clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance;
+
+  CVType bases = tpi.getType(record.DerivationList);
+  ArgListRecord base_list;
+  cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(bases, base_list));
+  if (base_list.ArgIndices.empty())
+    return clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance;
+
+  int base_count = 0;
+  for (TypeIndex ti : base_list.ArgIndices) {
+    CVType base = tpi.getType(ti);
+    if (base.kind() == LF_VBCLASS || base.kind() == LF_IVBCLASS)
+      return clang::MSInheritanceAttr::Spelling::Keyword_virtual_inheritance;
+    ++base_count;
+  }
+
+  if (base_count > 1)
+    return clang::MSInheritanceAttr::Keyword_multiple_inheritance;
+  return clang::MSInheritanceAttr::Keyword_single_inheritance;
+}
+
+static lldb::BasicType GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
+  switch (kind) {
+  case SimpleTypeKind::Boolean128:
+  case SimpleTypeKind::Boolean16:
+  case SimpleTypeKind::Boolean32:
+  case SimpleTypeKind::Boolean64:
+  case SimpleTypeKind::Boolean8:
+    return lldb::eBasicTypeBool;
+  case SimpleTypeKind::Byte:
+  case SimpleTypeKind::UnsignedCharacter:
+    return lldb::eBasicTypeUnsignedChar;
+  case SimpleTypeKind::NarrowCharacter:
+    return lldb::eBasicTypeChar;
+  case SimpleTypeKind::SignedCharacter:
+  case SimpleTypeKind::SByte:
+    return lldb::eBasicTypeSignedChar;
+  case SimpleTypeKind::Character16:
+    return lldb::eBasicTypeChar16;
+  case SimpleTypeKind::Character32:
+    return lldb::eBasicTypeChar32;
+  case SimpleTypeKind::Complex80:
+    return lldb::eBasicTypeLongDoubleComplex;
+  case SimpleTypeKind::Complex64:
+    return lldb::eBasicTypeDoubleComplex;
+  case SimpleTypeKind::Complex32:
+    return lldb::eBasicTypeFloatComplex;
+  case SimpleTypeKind::Float128:
+  case SimpleTypeKind::Float80:
+    return lldb::eBasicTypeLongDouble;
+  case SimpleTypeKind::Float64:
+    return lldb::eBasicTypeDouble;
+  case SimpleTypeKind::Float32:
+    return lldb::eBasicTypeFloat;
+  case SimpleTypeKind::Float16:
+    return lldb::eBasicTypeHalf;
+  case SimpleTypeKind::Int128:
+    return lldb::eBasicTypeInt128;
+  case SimpleTypeKind::Int64:
+  case SimpleTypeKind::Int64Quad:
+    return lldb::eBasicTypeLongLong;
+  case SimpleTypeKind::Int32:
+    return lldb::eBasicTypeInt;
+  case SimpleTypeKind::Int16:
+  case SimpleTypeKind::Int16Short:
+    return lldb::eBasicTypeShort;
+  case SimpleTypeKind::UInt128:
+    return lldb::eBasicTypeUnsignedInt128;
+  case SimpleTypeKind::UInt64:
+  case SimpleTypeKind::UInt64Quad:
+    return lldb::eBasicTypeUnsignedLongLong;
+  case SimpleTypeKind::HResult:
+  case SimpleTypeKind::UInt32:
+    return lldb::eBasicTypeUnsignedInt;
+  case SimpleTypeKind::UInt16:
+  case SimpleTypeKind::UInt16Short:
+    return lldb::eBasicTypeUnsignedShort;
+  case SimpleTypeKind::Int32Long:
+    return lldb::eBasicTypeLong;
+  case SimpleTypeKind::UInt32Long:
+    return lldb::eBasicTypeUnsignedLong;
+  case SimpleTypeKind::Void:
+    return lldb::eBasicTypeVoid;
+  case SimpleTypeKind::WideCharacter:
+    return lldb::eBasicTypeWChar;
+  default:
+    return lldb::eBasicTypeInvalid;
+  }
+}
+
+static size_t GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
+  switch (kind) {
+  case SimpleTypeKind::Boolean128:
+  case SimpleTypeKind::Int128:
+  case SimpleTypeKind::UInt128:
+  case SimpleTypeKind::Float128:
+    return 16;
+  case SimpleTypeKind::Complex80:
+  case SimpleTypeKind::Float80:
+    return 10;
+  case SimpleTypeKind::Boolean64:
+  case SimpleTypeKind::Complex64:
+  case SimpleTypeKind::UInt64:
+  case SimpleTypeKind::UInt64Quad:
+  case SimpleTypeKind::Float64:
+  case SimpleTypeKind::Int64:
+  case SimpleTypeKind::Int64Quad:
+    return 8;
+  case SimpleTypeKind::Boolean32:
+  case SimpleTypeKind::Character32:
+  case SimpleTypeKind::Complex32:
+  case SimpleTypeKind::Float32:
+  case SimpleTypeKind::Int32:
+  case SimpleTypeKind::Int32Long:
+  case SimpleTypeKind::UInt32Long:
+  case SimpleTypeKind::HResult:
+  case SimpleTypeKind::UInt32:
+    return 4;
+  case SimpleTypeKind::Boolean16:
+  case SimpleTypeKind::Character16:
+  case SimpleTypeKind::Float16:
+  case SimpleTypeKind::Int16:
+  case SimpleTypeKind::Int16Short:
+  case SimpleTypeKind::UInt16:
+  case SimpleTypeKind::UInt16Short:
+  case SimpleTypeKind::WideCharacter:
+    return 2;
+  case SimpleTypeKind::Boolean8:
+  case SimpleTypeKind::Byte:
+  case SimpleTypeKind::UnsignedCharacter:
+  case SimpleTypeKind::NarrowCharacter:
+  case SimpleTypeKind::SignedCharacter:
+  case SimpleTypeKind::SByte:
+    return 1;
+  case SimpleTypeKind::Void:
+  default:
+    return 0;
+  }
+}
+
+static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
+  switch (kind) {
+  case SimpleTypeKind::Boolean128:
+  case SimpleTypeKind::Boolean16:
+  case SimpleTypeKind::Boolean32:
+  case SimpleTypeKind::Boolean64:
+  case SimpleTypeKind::Boolean8:
+    return "bool";
+  case SimpleTypeKind::Byte:
+  case SimpleTypeKind::UnsignedCharacter:
+    return "unsigned char";
+  case SimpleTypeKind::NarrowCharacter:
+    return "char";
+  case SimpleTypeKind::SignedCharacter:
+  case SimpleTypeKind::SByte:
+    return "signed chr";
+  case SimpleTypeKind::Character16:
+    return "char16_t";
+  case SimpleTypeKind::Character32:
+    return "char32_t";
+  case SimpleTypeKind::Complex80:
+  case SimpleTypeKind::Complex64:
+  case SimpleTypeKind::Complex32:
+    return "complex";
+  case SimpleTypeKind::Float128:
+  case SimpleTypeKind::Float80:
+    return "long double";
+  case SimpleTypeKind::Float64:
+    return "double";
+  case SimpleTypeKind::Float32:
+    return "float";
+  case SimpleTypeKind::Float16:
+    return "single";
+  case SimpleTypeKind::Int128:
+    return "__int128";
+  case SimpleTypeKind::Int64:
+  case SimpleTypeKind::Int64Quad:
+    return "__int64";
+  case SimpleTypeKind::Int32:
+    return "int";
+  case SimpleTypeKind::Int16:
+    return "short";
+  case SimpleTypeKind::UInt128:
+    return "unsigned __int128";
+  case SimpleTypeKind::UInt64:
+  case SimpleTypeKind::UInt64Quad:
+    return "unsigned __int64";
+  case SimpleTypeKind::HResult:
+    return "HRESULT";
+  case SimpleTypeKind::UInt32:
+    return "unsigned";
+  case SimpleTypeKind::UInt16:
+  case SimpleTypeKind::UInt16Short:
+    return "unsigned short";
+  case SimpleTypeKind::Int32Long:
+    return "long";
+  case SimpleTypeKind::UInt32Long:
+    return "unsigned long";
+  case SimpleTypeKind::Void:
+    return "void";
+  case SimpleTypeKind::WideCharacter:
+    return "wchar_t";
+  default:
+    return "";
+  }
+}
+
+static bool IsClassRecord(TypeLeafKind kind) {
+  switch (kind) {
+  case LF_STRUCTURE:
+  case LF_CLASS:
+  case LF_INTERFACE:
+    return true;
+  default:
+    return false;
+  }
+}
+
+static PDB_SymType GetPdbSymType(TpiStream &tpi, TypeIndex ti) {
+  if (ti.isSimple()) {
+    if (ti.getSimpleMode() == SimpleTypeMode::Direct)
+      return PDB_SymType::BuiltinType;
+    return PDB_SymType::PointerType;
+  }
+
+  CVType cvt = tpi.getType(ti);
+  TypeLeafKind kind = cvt.kind();
+  if (kind != LF_MODIFIER)
+    return CVTypeToPDBType(kind);
+
+  // 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);
+}
+
+static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) {
+  switch (cr.Kind) {
+  case TypeRecordKind::Class:
+    return clang::TTK_Class;
+  case TypeRecordKind::Struct:
+    return clang::TTK_Struct;
+  case TypeRecordKind::Union:
+    return clang::TTK_Union;
+  case TypeRecordKind::Interface:
+    return clang::TTK_Interface;
+  case TypeRecordKind::Enum:
+    return clang::TTK_Enum;
+  default:
+    lldbassert(false && "Invalid tag record kind!");
+    return clang::TTK_Struct;
+  }
+}
+
 void SymbolFileNativePDB::Initialize() {
   PluginManager::RegisterPlugin(GetPluginNameStatic(),
                                 GetPluginDescriptionStatic(), CreateInstance,
@@ -216,6 +488,11 @@ void SymbolFileNativePDB::InitializeObje
   m_obj_load_address = m_obj_file->GetFileOffset();
   m_index->SetLoadAddress(m_obj_load_address);
   m_index->ParseSectionContribs();
+
+  TypeSystem *ts = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  m_clang = llvm::dyn_cast_or_null<ClangASTContext>(ts);
+  m_importer = llvm::make_unique<ClangASTImporter>();
+  lldbassert(m_clang);
 }
 
 uint32_t SymbolFileNativePDB::GetNumCompileUnits() {
@@ -295,6 +572,329 @@ SymbolFileNativePDB::CreateCompileUnit(c
   return cu_sp;
 }
 
+lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbSymUid type_uid,
+                                                     const ModifierRecord &mr) {
+  TpiStream &stream = m_index->tpi();
+
+  TypeSP t = GetOrCreateType(mr.ModifiedType);
+  CompilerType ct = t->GetForwardCompilerType();
+  if ((mr.Modifiers & ModifierOptions::Const) != ModifierOptions::None)
+    ct = ct.AddConstModifier();
+  if ((mr.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None)
+    ct = ct.AddVolatileModifier();
+  std::string name;
+  if (mr.ModifiedType.isSimple())
+    name = GetSimpleTypeName(mr.ModifiedType.getSimpleKind());
+  else
+    name = computeTypeName(stream.typeCollection(), mr.ModifiedType);
+  Declaration decl;
+  return std::make_shared<Type>(type_uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                ConstString(name), t->GetByteSize(), nullptr,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                ct, Type::eResolveStateFull);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreatePointerType(
+    PdbSymUid type_uid, const llvm::codeview::PointerRecord &pr) {
+  TypeSP pointee = GetOrCreateType(pr.ReferentType);
+  CompilerType pointee_ct = pointee->GetForwardCompilerType();
+  lldbassert(pointee_ct);
+  Declaration decl;
+
+  if (pr.isPointerToMember()) {
+    MemberPointerInfo mpi = pr.getMemberInfo();
+    TypeSP class_type = GetOrCreateType(mpi.ContainingType);
+
+    CompilerType ct = ClangASTContext::CreateMemberPointerType(
+        class_type->GetLayoutCompilerType(), pointee_ct);
+
+    return std::make_shared<Type>(
+        type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(),
+        pr.getSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+        Type::eResolveStateFull);
+  }
+
+  CompilerType pointer_ct = pointee_ct;
+  if (pr.getMode() == PointerMode::LValueReference)
+    pointer_ct = pointer_ct.GetLValueReferenceType();
+  else if (pr.getMode() == PointerMode::RValueReference)
+    pointer_ct = pointer_ct.GetRValueReferenceType();
+  else
+    pointer_ct = pointer_ct.GetPointerType();
+
+  if ((pr.getOptions() & PointerOptions::Const) != PointerOptions::None)
+    pointer_ct = pointer_ct.AddConstModifier();
+
+  if ((pr.getOptions() & PointerOptions::Volatile) != PointerOptions::None)
+    pointer_ct = pointer_ct.AddVolatileModifier();
+
+  if ((pr.getOptions() & PointerOptions::Restrict) != PointerOptions::None)
+    pointer_ct = pointer_ct.AddRestrictModifier();
+
+  return std::make_shared<Type>(type_uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                ConstString(), pr.getSize(), nullptr,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                pointer_ct, Type::eResolveStateFull);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) {
+  if (ti.getSimpleMode() != SimpleTypeMode::Direct) {
+    PdbSymUid uid =
+        PdbSymUid::makeTypeSymId(PDB_SymType::PointerType, ti, false);
+    TypeSP direct_sp = GetOrCreateType(ti.makeDirect());
+    CompilerType ct = direct_sp->GetFullCompilerType();
+    ct = ct.GetPointerType();
+    uint32_t pointer_size = 4;
+    switch (ti.getSimpleMode()) {
+    case SimpleTypeMode::FarPointer32:
+    case SimpleTypeMode::NearPointer32:
+      pointer_size = 4;
+      break;
+    case SimpleTypeMode::NearPointer64:
+      pointer_size = 8;
+      break;
+    default:
+      // 128-bit and 16-bit pointers unsupported.
+      return nullptr;
+    }
+    Declaration decl;
+    return std::make_shared<Type>(uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                  ConstString(), pointer_size, nullptr,
+                                  LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                  ct, Type::eResolveStateFull);
+  }
+
+  PdbSymUid uid = PdbSymUid::makeTypeSymId(PDB_SymType::BuiltinType, ti, false);
+  if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated)
+    return nullptr;
+
+  lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind());
+  lldbassert(bt != lldb::eBasicTypeInvalid);
+  CompilerType ct = m_clang->GetBasicType(bt);
+  size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind());
+
+  llvm::StringRef type_name = GetSimpleTypeName(ti.getSimpleKind());
+
+  Declaration decl;
+  return std::make_shared<Type>(uid.toOpaqueId(), m_clang->GetSymbolFile(),
+                                ConstString(type_name), size, nullptr,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                ct, Type::eResolveStateFull);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion(
+    PdbSymUid type_uid, llvm::StringRef name, size_t size,
+    clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) {
+
+  // Some UDT with trival ctor has zero length. Just ignore.
+  if (size == 0)
+    return nullptr;
+
+  // Ignore unnamed-tag UDTs.
+  name = DropNameScope(name);
+  if (name.empty())
+    return nullptr;
+
+  clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl();
+
+  lldb::AccessType access =
+      (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic;
+
+  ClangASTMetadata metadata;
+  metadata.SetUserID(type_uid.toOpaqueId());
+  metadata.SetIsDynamicCXXType(false);
+
+  CompilerType ct =
+      m_clang->CreateRecordType(decl_context, access, name.str().c_str(), ttk,
+                                lldb::eLanguageTypeC_plus_plus, &metadata);
+  lldbassert(ct.IsValid());
+
+  clang::CXXRecordDecl *record_decl =
+      m_clang->GetAsCXXRecordDecl(ct.GetOpaqueQualType());
+  lldbassert(record_decl);
+
+  clang::MSInheritanceAttr *attr = clang::MSInheritanceAttr::CreateImplicit(
+      *m_clang->getASTContext(), inheritance);
+  record_decl->addAttr(attr);
+
+  ClangASTContext::StartTagDeclarationDefinition(ct);
+
+  // Even if it's possible, don't complete it at this point. Just mark it
+  // forward resolved, and if/when LLDB needs the full definition, it can
+  // ask us.
+  ClangASTContext::SetHasExternalStorage(ct.GetOpaqueQualType(), true);
+
+  // 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,
+                                LLDB_INVALID_UID, Type::eEncodingIsUID, decl,
+                                ct, Type::eResolveStateForward);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid,
+                                                const ClassRecord &cr) {
+  clang::TagTypeKind ttk = TranslateUdtKind(cr);
+
+  clang::MSInheritanceAttr::Spelling inheritance =
+      GetMSInheritance(m_index->tpi().typeCollection(), cr);
+  return CreateClassStructUnion(type_uid, cr.getName(), 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,
+      clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance);
+}
+
+lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid,
+                                                const EnumRecord &er) {
+  llvm::StringRef name = DropNameScope(er.getName());
+
+  clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl();
+
+  Declaration decl;
+  TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);
+  CompilerType enum_ct = m_clang->CreateEnumerationType(
+      name.str().c_str(), decl_context, decl,
+      underlying_type->GetFullCompilerType(), er.isScoped());
+
+  ClangASTContext::StartTagDeclarationDefinition(enum_ct);
+
+  // We're just going to forward resolve this for now.  We'll complete
+  // it only if the user requests.
+  return std::make_shared<lldb_private::Type>(
+      type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(name),
+      underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID,
+      lldb_private::Type::eEncodingIsUID, decl, enum_ct,
+      lldb_private::Type::eResolveStateForward);
+}
+
+TypeSP SymbolFileNativePDB::CreateType(PdbSymUid type_uid) {
+  const PdbTypeSymId &tsid = type_uid.asTypeSym();
+  TypeIndex index(tsid.index);
+
+  if (index.getIndex() < TypeIndex::FirstNonSimpleIndex)
+    return CreateSimpleType(index);
+
+  TpiStream &stream = tsid.is_ipi ? m_index->ipi() : m_index->tpi();
+  CVType cvt = stream.getType(index);
+
+  if (cvt.kind() == LF_MODIFIER) {
+    ModifierRecord modifier;
+    llvm::cantFail(
+        TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier));
+    return CreateModifierType(type_uid, modifier);
+  }
+
+  if (cvt.kind() == LF_POINTER) {
+    PointerRecord pointer;
+    llvm::cantFail(
+        TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer));
+    return CreatePointerType(type_uid, pointer);
+  }
+
+  if (IsClassRecord(cvt.kind())) {
+    ClassRecord cr;
+    llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr));
+    return CreateTagType(type_uid, cr);
+  }
+
+  if (cvt.kind() == LF_ENUM) {
+    EnumRecord er;
+    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+    return CreateTagType(type_uid, er);
+  }
+
+  if (cvt.kind() == LF_UNION) {
+    UnionRecord ur;
+    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur));
+    return CreateTagType(type_uid, ur);
+  }
+
+  return nullptr;
+}
+
+TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbSymUid type_uid) {
+  // If they search for a UDT which is a forward ref, try and resolve the full
+  // decl and just map the forward ref uid to the full decl record.
+  llvm::Optional<PdbSymUid> full_decl_uid;
+  if (type_uid.tag() == PDB_SymType::UDT ||
+      type_uid.tag() == PDB_SymType::Enum) {
+    const PdbTypeSymId &type_id = type_uid.asTypeSym();
+    TypeIndex ti(type_id.index);
+    lldbassert(!ti.isSimple());
+    CVType cvt = m_index->tpi().getType(ti);
+
+    if (IsForwardRefUdt(cvt)) {
+      auto expected_full_ti = m_index->tpi().findFullDeclForForwardRef(ti);
+      if (!expected_full_ti)
+        llvm::consumeError(expected_full_ti.takeError());
+      else {
+        full_decl_uid = PdbSymUid::makeTypeSymId(
+            type_uid.tag(), *expected_full_ti, type_id.is_ipi);
+
+        // It's possible that a lookup would occur for the full decl causing it
+        // to be cached, then a second lookup would occur for the forward decl.
+        // We don't want to create a second full decl, so make sure the full
+        // decl hasn't already been cached.
+        auto full_iter = m_types.find(full_decl_uid->toOpaqueId());
+        if (full_iter != m_types.end()) {
+          TypeSP result = full_iter->second;
+          // Map the forward decl to the TypeSP for the full decl so we can take
+          // the fast path next time.
+          m_types[type_uid.toOpaqueId()] = result;
+          return result;
+        }
+      }
+    }
+  }
+
+  PdbSymUid best_uid = full_decl_uid ? *full_decl_uid : type_uid;
+  TypeSP result = CreateType(best_uid);
+  m_types[best_uid.toOpaqueId()] = result;
+  // If we had both a forward decl and a full decl, make both point to the new
+  // type.
+  if (full_decl_uid)
+    m_types[type_uid.toOpaqueId()] = result;
+
+  const PdbTypeSymId &type_id = best_uid.asTypeSym();
+  if (best_uid.tag() == PDB_SymType::UDT ||
+      best_uid.tag() == PDB_SymType::Enum) {
+    clang::TagDecl *record_decl =
+        m_clang->GetAsTagDecl(result->GetForwardCompilerType());
+    lldbassert(record_decl);
+
+    TypeIndex ti(type_id.index);
+    CVType cvt = m_index->tpi().getType(ti);
+    m_uid_to_decl[best_uid.toOpaqueId()] = record_decl;
+    m_decl_to_status[record_decl] =
+        DeclStatus(best_uid.toOpaqueId(), Type::eResolveStateForward);
+  }
+  return result;
+}
+
+TypeSP SymbolFileNativePDB::GetOrCreateType(PdbSymUid type_uid) {
+  lldbassert(PdbSymUid::isTypeSym(type_uid.tag()));
+  // We can't use try_emplace / overwrite here because the process of creating
+  // a type could create nested types, which could invalidate iterators.  So
+  // we have to do a 2-phase lookup / insert.
+  auto iter = m_types.find(type_uid.toOpaqueId());
+  if (iter != m_types.end())
+    return iter->second;
+
+  return CreateAndCacheType(type_uid);
+}
+
+lldb::TypeSP
+SymbolFileNativePDB::GetOrCreateType(llvm::codeview::TypeIndex ti) {
+  PDB_SymType pdbst = GetPdbSymType(m_index->tpi(), ti);
+  PdbSymUid tuid = PdbSymUid::makeTypeSymId(pdbst, ti, false);
+  return GetOrCreateType(tuid);
+}
+
 FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbSymUid func_uid,
                                                     const SymbolContext &sc) {
   lldbassert(func_uid.tag() == PDB_SymType::Function);
@@ -595,7 +1195,18 @@ uint32_t SymbolFileNativePDB::FindTypes(
     const CompilerDeclContext *parent_decl_ctx, bool append,
     uint32_t max_matches, llvm::DenseSet<SymbolFile *> &searched_symbol_files,
     TypeMap &types) {
-  return 0;
+  if (!append)
+    types.Clear();
+  if (!name)
+    return 0;
+
+  searched_symbol_files.clear();
+  searched_symbol_files.insert(this);
+
+  // There is an assumption 'name' is not a regex
+  size_t match_count = FindTypesByName(name.GetStringRef(), max_matches, types);
+
+  return match_count;
 }
 
 size_t
@@ -604,13 +1215,96 @@ SymbolFileNativePDB::FindTypes(const std
   return 0;
 }
 
+size_t SymbolFileNativePDB::FindTypesByName(llvm::StringRef name,
+                                            uint32_t max_matches,
+                                            TypeMap &types) {
+
+  size_t match_count = 0;
+  std::vector<TypeIndex> matches = m_index->tpi().findRecordsByName(name);
+  if (max_matches > 0 && max_matches < matches.size())
+    matches.resize(max_matches);
+
+  for (TypeIndex ti : matches) {
+    TypeSP type = GetOrCreateType(ti);
+    if (!type)
+      continue;
+
+    types.Insert(type);
+    ++match_count;
+  }
+  return match_count;
+}
+
 size_t SymbolFileNativePDB::ParseTypes(const SymbolContext &sc) { return 0; }
 
 Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) {
-  return nullptr;
+  auto iter = m_types.find(type_uid);
+  // lldb should not be passing us non-sensical type uids.  the only way it
+  // could have a type uid in the first place is if we handed it out, in which
+  // case we should know about the type.  So this is not a get-or-create type
+  // operation, it is strictly a get, and the type is guaranteed to exist.
+  //
+  // However, since the implementation is not yet complete, we don't currently
+  // support all possible use cases.  For example, we currently create all
+  // functions with indices of 0 for the signature type simply because this is
+  // not yet implemented.  At the time the function object is created we should
+  // be creating an lldb::TypeSP for this, adding it to the m_types, and
+  // returning a valid Type object for it and putting it in this map.  Once all
+  // cases like this are handled, we can promote this to an assert.
+  if (iter == m_types.end())
+    return nullptr;
+  return &*iter->second;
 }
 
 bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) {
+  // If this is not in our map, it's an error.
+  clang::TagDecl *tag_decl = m_clang->GetAsTagDecl(compiler_type);
+  lldbassert(tag_decl);
+  auto status_iter = m_decl_to_status.find(tag_decl);
+  lldbassert(status_iter != m_decl_to_status.end());
+
+  // If it's already complete, just return.
+  DeclStatus &status = status_iter->second;
+  if (status.status == Type::eResolveStateFull)
+    return true;
+
+  PdbSymUid uid = PdbSymUid::fromOpaqueId(status.uid);
+  lldbassert(uid.tag() == PDB_SymType::UDT || uid.tag() == PDB_SymType::Enum);
+
+  const PdbTypeSymId &type_id = uid.asTypeSym();
+
+  ClangASTContext::SetHasExternalStorage(compiler_type.GetOpaqueQualType(),
+                                         false);
+
+  // In CreateAndCacheType, we already go out of our way to resolve forward
+  // ref UDTs to full decls, and the uids we vend out always refer to full
+  // decls if a full decl exists in the debug info.  So if we don't have a full
+  // decl here, it means one doesn't exist in the debug info, and we can't
+  // complete the type.
+  CVType cvt = m_index->tpi().getType(TypeIndex(type_id.index));
+  if (IsForwardRefUdt(cvt))
+    return false;
+
+  auto types_iter = m_types.find(uid.toOpaqueId());
+  lldbassert(types_iter != m_types.end());
+
+  TypeIndex field_list_ti = GetFieldListIndex(cvt);
+  CVType field_list_cvt = m_index->tpi().getType(field_list_ti);
+  if (field_list_cvt.kind() != LF_FIELDLIST)
+    return false;
+
+  // Visit all members of this class, then perform any finalization necessary
+  // to complete the class.
+  UdtRecordCompleter completer(uid, compiler_type, *tag_decl, *this);
+  auto error =
+      llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
+  completer.complete();
+
+  status.status = Type::eResolveStateFull;
+  if (!error)
+    return true;
+
+  llvm::consumeError(std::move(error));
   return false;
 }
 

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=345047&r1=345046&r2=345047&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h (original)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h Tue Oct 23 09:37:53 2018
@@ -10,6 +10,7 @@
 #ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
 #define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
 
+#include "lldb/Symbol/ClangASTImporter.h"
 #include "lldb/Symbol/SymbolFile.h"
 
 #include "llvm/ADT/DenseMap.h"
@@ -144,22 +145,63 @@ public:
   llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); }
   const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); }
 
+  ClangASTContext &GetASTContext() { return *m_clang; }
+  ClangASTImporter &GetASTImporter() { return *m_importer; }
+
 private:
+  void AddBaseClassesToLayout(CompilerType &derived_ct,
+                              ClangASTImporter::LayoutInfo &layout,
+                              const llvm::codeview::ClassRecord &record);
+  void AddMembersToLayout(ClangASTImporter::LayoutInfo &layout,
+                          const llvm::codeview::TagRecord &record);
+  void AddMethodsToLayout(ClangASTImporter::LayoutInfo &layout,
+                          const llvm::codeview::TagRecord &record);
+
+  size_t FindTypesByName(llvm::StringRef name, uint32_t max_matches,
+                         TypeMap &types);
+
+  lldb::TypeSP CreateModifierType(PdbSymUid type_uid,
+                                  const llvm::codeview::ModifierRecord &mr);
+  lldb::TypeSP CreatePointerType(PdbSymUid type_uid,
+                                 const llvm::codeview::PointerRecord &pr);
+  lldb::TypeSP CreateSimpleType(llvm::codeview::TypeIndex ti);
+  lldb::TypeSP CreateTagType(PdbSymUid type_uid,
+                             const llvm::codeview::ClassRecord &cr);
+  lldb::TypeSP CreateTagType(PdbSymUid type_uid,
+                             const llvm::codeview::EnumRecord &er);
+  lldb::TypeSP CreateTagType(PdbSymUid type_uid,
+                             const llvm::codeview::UnionRecord &ur);
+  lldb::TypeSP
+  CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size,
+                         clang::TagTypeKind ttk,
+                         clang::MSInheritanceAttr::Spelling inheritance);
+
   lldb::FunctionSP GetOrCreateFunction(PdbSymUid func_uid,
                                        const SymbolContext &sc);
   lldb::CompUnitSP GetOrCreateCompileUnit(const CompilandIndexItem &cci);
+  lldb::TypeSP GetOrCreateType(PdbSymUid type_uid);
+  lldb::TypeSP GetOrCreateType(llvm::codeview::TypeIndex ti);
 
   lldb::FunctionSP CreateFunction(PdbSymUid func_uid, const SymbolContext &sc);
   lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci);
+  lldb::TypeSP CreateType(PdbSymUid type_uid);
+  lldb::TypeSP CreateAndCacheType(PdbSymUid type_uid);
 
   llvm::BumpPtrAllocator m_allocator;
 
   lldb::addr_t m_obj_load_address = 0;
 
   std::unique_ptr<PdbIndex> m_index;
+  std::unique_ptr<ClangASTImporter> m_importer;
+  ClangASTContext *m_clang = nullptr;
+
+  llvm::DenseMap<clang::TagDecl *, DeclStatus> m_decl_to_status;
+
+  llvm::DenseMap<lldb::user_id_t, clang::TagDecl *> m_uid_to_decl;
 
   llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
   llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
+  llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
 };
 
 } // namespace npdb

Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp?rev=345047&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp Tue Oct 23 09:37:53 2018
@@ -0,0 +1,188 @@
+#include "UdtRecordCompleter.h"
+
+#include "PdbIndex.h"
+#include "PdbSymUid.h"
+#include "PdbUtil.h"
+#include "SymbolFileNativePDB.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::npdb;
+
+using Error = llvm::Error;
+
+UdtRecordCompleter::UdtRecordCompleter(PdbSymUid uid, CompilerType &derived_ct,
+                                       clang::TagDecl &tag_decl,
+                                       SymbolFileNativePDB &symbol_file)
+    : m_uid(uid), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
+      m_symbol_file(symbol_file) {
+  TpiStream &tpi = symbol_file.m_index->tpi();
+  TypeIndex ti(uid.asTypeSym().index);
+  CVType cvt = tpi.getType(ti);
+  switch (cvt.kind()) {
+  case LF_ENUM:
+    lldbassert(uid.tag() == PDB_SymType::Enum);
+    llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er));
+    break;
+  case LF_UNION:
+    lldbassert(uid.tag() == PDB_SymType::UDT);
+    llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur));
+    break;
+  case LF_CLASS:
+  case LF_STRUCTURE:
+    lldbassert(uid.tag() == PDB_SymType::UDT);
+    llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr));
+    break;
+  default:
+    llvm_unreachable("unreachable!");
+  }
+}
+
+lldb::opaque_compiler_type_t UdtRecordCompleter::AddBaseClassForTypeIndex(
+    llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access) {
+  TypeSP base_type = m_symbol_file.GetOrCreateType(ti);
+  CompilerType base_ct = base_type->GetFullCompilerType();
+
+  CVType udt_cvt = m_symbol_file.m_index->tpi().getType(ti);
+
+  lldb::opaque_compiler_type_t base_qt = base_ct.GetOpaqueQualType();
+  clang::CXXBaseSpecifier *base_spec =
+      m_symbol_file.GetASTContext().CreateBaseClassSpecifier(
+          base_qt, TranslateMemberAccess(access), false,
+          udt_cvt.kind() == LF_CLASS);
+
+  m_bases.push_back(base_spec);
+  return base_qt;
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           BaseClassRecord &base) {
+  lldb::opaque_compiler_type_t base_qt =
+      AddBaseClassForTypeIndex(base.Type, base.getAccess());
+
+  auto decl = m_symbol_file.GetASTContext().GetAsCXXRecordDecl(base_qt);
+  lldbassert(decl);
+
+  auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset());
+  m_layout.base_offsets.insert(std::make_pair(decl, offset));
+
+  return llvm::Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           VirtualBaseClassRecord &base) {
+  AddBaseClassForTypeIndex(base.BaseType, base.getAccess());
+
+  // FIXME: Handle virtual base offsets.
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           ListContinuationRecord &cont) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           VFPtrRecord &vfptr) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(
+    CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) {
+  TypeSP member_type = m_symbol_file.GetOrCreateType(static_data_member.Type);
+  CompilerType complete_member_type = member_type->GetFullCompilerType();
+
+  lldb::AccessType access =
+      TranslateMemberAccess(static_data_member.getAccess());
+  ClangASTContext::AddVariableToRecordType(
+      m_derived_ct, static_data_member.Name.str().c_str(), complete_member_type,
+      access);
+
+  // FIXME: Add a PdbSymUid namespace for field list members and update
+  // the m_uid_to_decl map with this decl.
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           NestedTypeRecord &nested) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           DataMemberRecord &data_member) {
+
+  TypeSP member_type = m_symbol_file.GetOrCreateType(data_member.Type);
+  CompilerType complete_member_type = member_type->GetFullCompilerType();
+
+  lldb::AccessType access = TranslateMemberAccess(data_member.getAccess());
+
+  clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType(
+      m_derived_ct, data_member.Name.str().c_str(), complete_member_type,
+      access, 0);
+  // FIXME: Add a PdbSymUid namespace for field list members and update
+  // the m_uid_to_decl map with this decl.
+
+  uint64_t offset = data_member.FieldOffset * 8;
+  m_layout.field_offsets.insert(std::make_pair(decl, offset));
+
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           OneMethodRecord &one_method) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           OverloadedMethodRecord &overloaded) {
+  return Error::success();
+}
+
+Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
+                                           EnumeratorRecord &enumerator) {
+  ClangASTContext &clang = m_symbol_file.GetASTContext();
+
+  Declaration decl;
+  llvm::StringRef name = DropNameScope(enumerator.getName());
+  lldbassert(m_uid.tag() == PDB_SymType::Enum);
+  TypeSP underlying_type =
+      m_symbol_file.GetOrCreateType(m_cvr.er.getUnderlyingType());
+
+  lldb::opaque_compiler_type_t enum_qt = m_derived_ct.GetOpaqueQualType();
+
+  CompilerType enumerator_type = clang.GetEnumerationIntegerType(enum_qt);
+  uint64_t byte_size = underlying_type->GetByteSize();
+  clang.AddEnumerationValueToEnumerationType(
+      m_derived_ct.GetOpaqueQualType(), enumerator_type, decl,
+      name.str().c_str(), enumerator.Value.getSExtValue(),
+      byte_size * 8);
+  return Error::success();
+}
+
+void UdtRecordCompleter::complete() {
+  ClangASTContext &clang = m_symbol_file.GetASTContext();
+  clang.SetBaseClassesForClassType(m_derived_ct.GetOpaqueQualType(),
+                                   m_bases.data(), m_bases.size());
+  ClangASTContext::DeleteBaseClassSpecifiers(m_bases.data(), m_bases.size());
+
+  clang.AddMethodOverridesForCXXRecordType(m_derived_ct.GetOpaqueQualType());
+  ClangASTContext::BuildIndirectFields(m_derived_ct);
+  ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct);
+
+  if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) {
+    m_symbol_file.GetASTImporter().InsertRecordDecl(record_decl, m_layout);
+  }
+}
\ No newline at end of file

Added: lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h?rev=345047&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h (added)
+++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h Tue Oct 23 09:37:53 2018
@@ -0,0 +1,68 @@
+//===-- SymbolFileNativePDB.h -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H
+
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "llvm/DebugInfo/CodeView/CVRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+#include "PdbSymUid.h"
+
+namespace clang {
+class CXXBaseSpecifier;
+class TagDecl;
+} // namespace clang
+
+namespace lldb_private {
+class Type;
+class CompilerType;
+namespace npdb {
+class SymbolFileNativePDB;
+
+class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
+  union UdtTagRecord {
+    UdtTagRecord() {}
+    llvm::codeview::UnionRecord ur;
+    llvm::codeview::ClassRecord cr;
+    llvm::codeview::EnumRecord er;
+  } m_cvr;
+
+  PdbSymUid m_uid;
+  CompilerType &m_derived_ct;
+  clang::TagDecl &m_tag_decl;
+  SymbolFileNativePDB &m_symbol_file;
+  std::vector<clang::CXXBaseSpecifier *> m_bases;
+  ClangASTImporter::LayoutInfo m_layout;
+
+public:
+  UdtRecordCompleter(PdbSymUid uid, CompilerType &derived_ct,
+                     clang::TagDecl &tag_decl,
+                     SymbolFileNativePDB &symbol_file);
+
+#define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
+  llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR,            \
+                               llvm::codeview::Name##Record &Record) override;
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+
+  void complete();
+
+private:
+  lldb::opaque_compiler_type_t
+  AddBaseClassForTypeIndex(llvm::codeview::TypeIndex ti,
+                           llvm::codeview::MemberAccess access);
+};
+
+} // namespace npdb
+} // namespace lldb_private
+
+#endif // LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H




More information about the lldb-commits mailing list