summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit8
-rw-r--r--lldb/lit/SymbolFile/NativePDB/tag-types.cpp236
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp6
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp700
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h42
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp188
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h68
8 files changed, 1246 insertions, 3 deletions
diff --git a/lldb/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit b/lldb/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
new file mode 100644
index 00000000000..c50e18101b1
--- /dev/null
+++ b/lldb/lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit
@@ -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
diff --git a/lldb/lit/SymbolFile/NativePDB/tag-types.cpp b/lldb/lit/SymbolFile/NativePDB/tag-types.cpp
new file mode 100644
index 00000000000..ce28bb9b6c9
--- /dev/null
+++ b/lldb/lit/SymbolFile/NativePDB/tag-types.cpp
@@ -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'
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
index dc459ec020d..c463cd80b59 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
@@ -3,6 +3,7 @@ add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN
PdbIndex.cpp
PdbUtil.cpp
SymbolFileNativePDB.cpp
+ UdtRecordCompleter.cpp
LINK_LIBS
clangAST
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
index c9bd9a48568..cda9508c07a 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
@@ -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::pdb::PDBFile> file) {
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
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 748c0de6258..9aa5ecbf5e3 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -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 CompilandIndexItem &cci,
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::InitializeObject() {
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(const CompilandIndexItem &cci) {
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::vector<CompilerContext> &context,
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;
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 2a5b5471a1d..2b1f893c1ea 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -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
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
new file mode 100644
index 00000000000..905a3f0501a
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -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
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
new file mode 100644
index 00000000000..76c1ad54e0a
--- /dev/null
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -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
OpenPOWER on IntegriCloud