Index: lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit =================================================================== --- lit/SymbolFile/NativePDB/Inputs/tag-types.lldbinit +++ 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 Index: lit/SymbolFile/NativePDB/tag-types.cpp =================================================================== --- lit/SymbolFile/NativePDB/tag-types.cpp +++ 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' Index: source/Plugins/SymbolFile/NativePDB/CMakeLists.txt =================================================================== --- source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -3,6 +3,7 @@ PdbIndex.cpp PdbUtil.cpp SymbolFileNativePDB.cpp + UdtRecordCompleter.cpp LINK_LIBS clangAST Index: source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp =================================================================== --- source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp +++ 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 @@ 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 @@ : 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 Index: source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h =================================================================== --- source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ 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 @@ 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 m_index; + std::unique_ptr m_importer; + ClangASTContext *m_clang = nullptr; + + llvm::DenseMap m_decl_to_status; + + llvm::DenseMap m_uid_to_decl; llvm::DenseMap m_functions; llvm::DenseMap m_compilands; + llvm::DenseMap m_types; }; } // namespace npdb Index: source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ 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 @@ 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(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(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 @@ 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(ts); + m_importer = llvm::make_unique(); + lldbassert(m_clang); } uint32_t SymbolFileNativePDB::GetNumCompileUnits() { @@ -295,6 +572,329 @@ 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_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_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_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(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(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_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( + 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(cvt, modifier)); + return CreateModifierType(type_uid, modifier); + } + + if (cvt.kind() == LF_POINTER) { + PointerRecord pointer; + llvm::cantFail( + TypeDeserializer::deserializeAs(cvt, pointer)); + return CreatePointerType(type_uid, pointer); + } + + if (IsClassRecord(cvt.kind())) { + ClassRecord cr; + llvm::cantFail(TypeDeserializer::deserializeAs(cvt, cr)); + return CreateTagType(type_uid, cr); + } + + if (cvt.kind() == LF_ENUM) { + EnumRecord er; + llvm::cantFail(TypeDeserializer::deserializeAs(cvt, er)); + return CreateTagType(type_uid, er); + } + + if (cvt.kind() == LF_UNION) { + UnionRecord ur; + llvm::cantFail(TypeDeserializer::deserializeAs(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 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 @@ const CompilerDeclContext *parent_decl_ctx, bool append, uint32_t max_matches, llvm::DenseSet &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 @@ return 0; } +size_t SymbolFileNativePDB::FindTypesByName(llvm::StringRef name, + uint32_t max_matches, + TypeMap &types) { + + size_t match_count = 0; + std::vector 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; } Index: source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h =================================================================== --- source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ 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 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 Index: source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp =================================================================== --- source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ 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(cvt, m_cvr.er)); + break; + case LF_UNION: + lldbassert(uid.tag() == PDB_SymType::UDT); + llvm::cantFail(TypeDeserializer::deserializeAs(cvt, m_cvr.ur)); + break; + case LF_CLASS: + case LF_STRUCTURE: + lldbassert(uid.tag() == PDB_SymType::UDT); + llvm::cantFail(TypeDeserializer::deserializeAs(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(&m_tag_decl)) { + m_symbol_file.GetASTImporter().InsertRecordDecl(record_decl, m_layout); + } +} \ No newline at end of file