summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp')
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp700
1 files changed, 697 insertions, 3 deletions
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;
}
OpenPOWER on IntegriCloud