diff options
Diffstat (limited to 'lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp')
| -rw-r--r-- | lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 700 | 
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;  } | 

