diff options
10 files changed, 1374 insertions, 814 deletions
diff --git a/lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp b/lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp index ff7f6bbd479..87cd23d35af 100644 --- a/lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp +++ b/lldb/lit/SymbolFile/NativePDB/function-types-classes.cpp @@ -108,10 +108,10 @@ auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>; // CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}} // CHECK: TranslationUnitDecl {{.*}} -// CHECK: |-CXXRecordDecl {{.*}} class C definition -// CHECK: |-CXXRecordDecl {{.*}} union U definition +// CHECK: |-CXXRecordDecl {{.*}} class C +// CHECK: |-CXXRecordDecl {{.*}} union U // CHECK: |-EnumDecl {{.*}} E -// CHECK: |-CXXRecordDecl {{.*}} struct S definition +// CHECK: |-CXXRecordDecl {{.*}} struct S // CHECK: |-CXXRecordDecl {{.*}} struct B // CHECK: | |-CXXRecordDecl {{.*}} struct A // CHECK: | | |-CXXRecordDecl {{.*}} struct S @@ -119,11 +119,11 @@ auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>; // CHECK: | |-CXXRecordDecl {{.*}} struct C // CHECK: | | |-CXXRecordDecl {{.*}} struct S // CHECK: | `-NamespaceDecl {{.*}} B -// CHECK: | `-CXXRecordDecl {{.*}} struct S definition -// CHECK: |-CXXRecordDecl {{.*}} struct TC<int> definition -// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct TC<int>> definition -// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct A::B::S> definition -// CHECK: |-CXXRecordDecl {{.*}} struct TC<void> definition +// CHECK: | `-CXXRecordDecl {{.*}} struct S +// CHECK: |-CXXRecordDecl {{.*}} struct TC<int> +// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct TC<int>> +// CHECK: |-CXXRecordDecl {{.*}} struct TC<struct A::B::S> +// CHECK: |-CXXRecordDecl {{.*}} struct TC<void> // CHECK: |-CXXRecordDecl {{.*}} struct Incomplete int main(int argc, char **argv) { diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt index 72ebfc313df..a43bab68bbb 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN CompileUnitIndex.cpp DWARFLocationExpression.cpp + PdbASTBuilder.cpp PdbIndex.cpp PdbSymUid.cpp PdbUtil.cpp diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp new file mode 100644 index 00000000000..956e56f504d --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -0,0 +1,865 @@ +#include "PdbAstBuilder.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Demangle/MicrosoftDemangle.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangUtil.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/LLDBAssert.h" + +#include "PdbUtil.h" +#include "UdtRecordCompleter.h" + +using namespace lldb_private; +using namespace lldb_private::npdb; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static llvm::Optional<PdbCompilandSymId> FindSymbolScope(PdbIndex &index, + PdbCompilandSymId id) { + CVSymbol sym = index.ReadSymbolRecord(id); + if (symbolOpensScope(sym.kind())) { + // If this exact symbol opens a scope, we can just directly access its + // parent. + id.offset = getScopeParentOffset(sym); + // Global symbols have parent offset of 0. Return llvm::None to indicate + // this. + if (id.offset == 0) + return llvm::None; + return id; + } + + // Otherwise we need to start at the beginning and iterate forward until we + // reach (or pass) this particular symbol + CompilandIndexItem &cii = index.compilands().GetOrCreateCompiland(id.modi); + const CVSymbolArray &syms = cii.m_debug_stream.getSymbolArray(); + + auto begin = syms.begin(); + auto end = syms.at(id.offset); + std::vector<PdbCompilandSymId> scope_stack; + + while (begin != end) { + if (id.offset == begin.offset()) { + // We have a match! Return the top of the stack + if (scope_stack.empty()) + return llvm::None; + return scope_stack.back(); + } + if (begin.offset() > id.offset) { + // We passed it. We couldn't even find this symbol record. + lldbassert(false && "Invalid compiland symbol id!"); + return llvm::None; + } + + // We haven't found the symbol yet. Check if we need to open or close the + // scope stack. + if (symbolOpensScope(begin->kind())) { + // We can use the end offset of the scope to determine whether or not + // we can just outright skip this entire scope. + uint32_t scope_end = getScopeEndOffset(*begin); + if (scope_end < id.modi) { + begin = syms.at(scope_end); + } else { + // The symbol we're looking for is somewhere in this scope. + scope_stack.emplace_back(id.modi, begin.offset()); + } + } else if (symbolEndsScope(begin->kind())) { + scope_stack.pop_back(); + } + ++begin; + } + + return llvm::None; +} + +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; + } +} + +static bool IsCVarArgsFunction(llvm::ArrayRef<TypeIndex> args) { + if (args.empty()) + return false; + return args.back() == TypeIndex::None(); +} + +static bool +AnyScopesHaveTemplateParams(llvm::ArrayRef<llvm::ms_demangle::Node *> scopes) { + for (llvm::ms_demangle::Node *n : scopes) { + auto *idn = static_cast<llvm::ms_demangle::IdentifierNode *>(n); + if (idn->TemplateParams) + return true; + } + return false; +} + +static ClangASTContext &GetClangASTContext(ObjectFile &obj) { + TypeSystem *ts = + obj.GetModule()->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + lldbassert(ts); + return static_cast<ClangASTContext &>(*ts); +} + +static llvm::Optional<clang::CallingConv> +TranslateCallingConvention(llvm::codeview::CallingConvention conv) { + using CC = llvm::codeview::CallingConvention; + switch (conv) { + + case CC::NearC: + case CC::FarC: + return clang::CallingConv::CC_C; + case CC::NearPascal: + case CC::FarPascal: + return clang::CallingConv::CC_X86Pascal; + case CC::NearFast: + case CC::FarFast: + return clang::CallingConv::CC_X86FastCall; + case CC::NearStdCall: + case CC::FarStdCall: + return clang::CallingConv::CC_X86StdCall; + case CC::ThisCall: + return clang::CallingConv::CC_X86ThisCall; + case CC::NearVector: + return clang::CallingConv::CC_X86VectorCall; + default: + return llvm::None; + } +} + +static llvm::Optional<CVTagRecord> +GetNestedTagRecord(const NestedTypeRecord &Record, const CVTagRecord &parent, + TpiStream &tpi) { + // An LF_NESTTYPE is essentially a nested typedef / using declaration, but it + // is also used to indicate the primary definition of a nested class. That is + // to say, if you have: + // struct A { + // struct B {}; + // using C = B; + // }; + // Then in the debug info, this will appear as: + // LF_STRUCTURE `A::B` [type index = N] + // LF_STRUCTURE `A` + // LF_NESTTYPE [name = `B`, index = N] + // LF_NESTTYPE [name = `C`, index = N] + // In order to accurately reconstruct the decl context hierarchy, we need to + // know which ones are actual definitions and which ones are just aliases. + + // If it's a simple type, then this is something like `using foo = int`. + if (Record.Type.isSimple()) + return llvm::None; + + CVType cvt = tpi.getType(Record.Type); + + if (!IsTagRecord(cvt)) + return llvm::None; + + // If it's an inner definition, then treat whatever name we have here as a + // single component of a mangled name. So we can inject it into the parent's + // mangled name to see if it matches. + CVTagRecord child = CVTagRecord::create(cvt); + std::string qname = parent.asTag().getUniqueName(); + if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4) + return llvm::None; + + // qname[3] is the tag type identifier (struct, class, union, etc). Since the + // inner tag type is not necessarily the same as the outer tag type, re-write + // it to match the inner tag type. + qname[3] = child.asTag().getUniqueName()[3]; + std::string piece = Record.Name; + piece.push_back('@'); + qname.insert(4, std::move(piece)); + if (qname != child.asTag().UniqueName) + return llvm::None; + + return std::move(child); +} + +PdbAstBuilder::PdbAstBuilder(ObjectFile &obj, PdbIndex &index) + : m_index(index), m_clang(GetClangASTContext(obj)) { + BuildParentMap(); +} + +clang::DeclContext &PdbAstBuilder::GetTranslationUnitDecl() { + return *m_clang.GetTranslationUnitDecl(); +} + +std::pair<clang::DeclContext *, std::string> +PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { + // FIXME: Move this to GetDeclContextContainingUID. + + llvm::ms_demangle::Demangler demangler; + StringView sv(record.UniqueName.begin(), record.UniqueName.size()); + llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv); + llvm::ms_demangle::IdentifierNode *idn = + ttn->QualifiedName->getUnqualifiedIdentifier(); + std::string uname = idn->toString(); + + llvm::ms_demangle::NodeArrayNode *name_components = + ttn->QualifiedName->Components; + llvm::ArrayRef<llvm::ms_demangle::Node *> scopes(name_components->Nodes, + name_components->Count - 1); + + clang::DeclContext *context = m_clang.GetTranslationUnitDecl(); + + // If this type doesn't have a parent type in the debug info, then the best we + // can do is to say that it's either a series of namespaces (if the scope is + // non-empty), or the translation unit (if the scope is empty). + auto parent_iter = m_parent_types.find(ti); + if (parent_iter == m_parent_types.end()) { + if (scopes.empty()) + return {context, uname}; + + // If there is no parent in the debug info, but some of the scopes have + // template params, then this is a case of bad debug info. See, for + // example, llvm.org/pr39607. We don't want to create an ambiguity between + // a NamespaceDecl and a CXXRecordDecl, so instead we create a class at + // global scope with the fully qualified name. + if (AnyScopesHaveTemplateParams(scopes)) + return {context, record.Name}; + + for (llvm::ms_demangle::Node *scope : scopes) { + auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope); + std::string str = nii->toString(); + context = m_clang.GetUniqueNamespaceDeclaration(str.c_str(), context); + } + return {context, uname}; + } + + // Otherwise, all we need to do is get the parent type of this type and + // recurse into our lazy type creation / AST reconstruction logic to get an + // LLDB TypeSP for the parent. This will cause the AST to automatically get + // the right DeclContext created for any parent. + clang::QualType parent_qt = GetOrCreateType(parent_iter->second); + + context = clang::TagDecl::castToDeclContext(parent_qt->getAsTagDecl()); + return {context, uname}; +} + +void PdbAstBuilder::BuildParentMap() { + LazyRandomTypeCollection &types = m_index.tpi().typeCollection(); + + for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) { + CVType type = types.getType(*ti); + if (!IsTagRecord(type)) + continue; + + CVTagRecord tag = CVTagRecord::create(type); + // We're looking for LF_NESTTYPE records in the field list, so ignore + // forward references (no field list), and anything without a nested class + // (since there won't be any LF_NESTTYPE records). + if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass()) + continue; + + struct ProcessTpiStream : public TypeVisitorCallbacks { + ProcessTpiStream(PdbIndex &index, TypeIndex parent, + const CVTagRecord &parent_cvt, + llvm::DenseMap<TypeIndex, TypeIndex> &parents) + : index(index), parents(parents), parent(parent), + parent_cvt(parent_cvt) {} + + PdbIndex &index; + llvm::DenseMap<TypeIndex, TypeIndex> &parents; + TypeIndex parent; + const CVTagRecord &parent_cvt; + + llvm::Error visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Record) override { + llvm::Optional<CVTagRecord> tag = + GetNestedTagRecord(Record, parent_cvt, index.tpi()); + if (!tag) + return llvm::ErrorSuccess(); + + parents[Record.Type] = parent; + if (!tag->asTag().isForwardRef()) + return llvm::ErrorSuccess(); + + llvm::Expected<TypeIndex> full_decl = + index.tpi().findFullDeclForForwardRef(Record.Type); + if (!full_decl) { + llvm::consumeError(full_decl.takeError()); + return llvm::ErrorSuccess(); + } + parents[*full_decl] = parent; + return llvm::ErrorSuccess(); + } + }; + + CVType field_list = m_index.tpi().getType(tag.asTag().FieldList); + ProcessTpiStream process(m_index, *ti, tag, m_parent_types); + llvm::Error error = visitMemberRecordStream(field_list.data(), process); + if (error) + llvm::consumeError(std::move(error)); + } +} + +clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) { + CVSymbol cvs = m_index.ReadSymbolRecord(id); + + switch (cvs.kind()) { + case S_GPROC32: + case S_LPROC32: + return GetOrCreateFunctionDecl(id); + case S_GDATA32: + case S_LDATA32: + case S_GTHREAD32: + case S_CONSTANT: + // global variable + return nullptr; + case S_BLOCK32: + return GetOrCreateBlockDecl(id); + case S_REGISTER: + case S_REGREL32: + case S_LOCAL: { + clang::DeclContext *scope = GetParentDeclContext(id); + clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope); + PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid); + return GetOrCreateLocalVariableDecl(scope_id, id); + } + default: + return nullptr; + } +} + +clang::Decl *PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) { + if (clang::Decl *result = TryGetDecl(uid)) + return result; + + clang::Decl *result = nullptr; + switch (uid.kind()) { + case PdbSymUidKind::CompilandSym: + result = GetOrCreateSymbolForId(uid.asCompilandSym()); + break; + case PdbSymUidKind::Type: { + clang::QualType qt = GetOrCreateType(uid.asTypeSym()); + if (auto *tag = qt->getAsTagDecl()) { + result = tag; + break; + } + return nullptr; + } + default: + return nullptr; + } + m_uid_to_decl[toOpaqueUid(uid)] = result; + return result; +} + +clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) { + clang::Decl *decl = GetOrCreateDeclForUid(uid); + if (!decl) + return nullptr; + + return clang::Decl::castToDeclContext(decl); +} + +clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) { + // We must do this *without* calling GetOrCreate on the current uid, as + // that would be an infinite recursion. + switch (uid.kind()) { + case PdbSymUidKind::CompilandSym: { + llvm::Optional<PdbCompilandSymId> scope = + FindSymbolScope(m_index, uid.asCompilandSym()); + if (!scope) + return &GetTranslationUnitDecl(); + return GetOrCreateDeclContextForUid(*scope); + } + case PdbSymUidKind::Type: + // It could be a namespace, class, or global. We don't support nested + // functions yet. Anyway, we just need to consult the parent type map. + break; + case PdbSymUidKind::FieldListMember: + // In this case the parent DeclContext is the one for the class that this + // member is inside of. + break; + default: + break; + } + return &GetTranslationUnitDecl(); +} + +bool PdbAstBuilder::CompleteType(clang::QualType qt) { + clang::TagDecl *tag = qt->getAsTagDecl(); + if (!tag) + return false; + + return CompleteTagDecl(*tag); +} + +bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { + // If this is not in our map, it's an error. + auto status_iter = m_decl_to_status.find(&tag); + lldbassert(status_iter != m_decl_to_status.end()); + + // If it's already complete, just return. + DeclStatus &status = status_iter->second; + if (status.resolved) + return true; + + PdbTypeSymId type_id = PdbSymUid(status.uid).asTypeSym(); + + lldbassert(IsTagRecord(type_id, m_index.tpi())); + + clang::QualType tag_qt = m_clang.getASTContext()->getTypeDeclType(&tag); + ClangASTContext::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false); + + TypeIndex tag_ti = type_id.index; + CVType cvt = m_index.tpi().getType(tag_ti); + if (cvt.kind() == LF_MODIFIER) + tag_ti = LookThroughModifierRecord(cvt); + + PdbTypeSymId best_ti = GetBestPossibleDecl(tag_ti, m_index.tpi()); + cvt = m_index.tpi().getType(best_ti.index); + lldbassert(IsTagRecord(cvt)); + + if (IsForwardRefUdt(cvt)) { + // If we can't find a full decl for this forward ref anywhere in the debug + // info, then we have no way to complete it. + return false; + } + + 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. + CompilerType ct = ToCompilerType(tag_qt); + UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index.tpi()); + auto error = + llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer); + completer.complete(); + + status.resolved = true; + if (!error) + return true; + + llvm::consumeError(std::move(error)); + return false; +} + +clang::QualType PdbAstBuilder::CreateSimpleType(TypeIndex ti) { + if (ti == TypeIndex::NullptrT()) + return GetBasicType(lldb::eBasicTypeNullPtr); + + if (ti.getSimpleMode() != SimpleTypeMode::Direct) { + clang::QualType direct_type = GetOrCreateType(ti.makeDirect()); + return m_clang.getASTContext()->getPointerType(direct_type); + } + + if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated) + return {}; + + lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind()); + if (bt == lldb::eBasicTypeInvalid) + return {}; + + return GetBasicType(bt); +} + +clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) { + clang::QualType pointee_type = GetOrCreateType(pointer.ReferentType); + + if (pointer.isPointerToMember()) { + MemberPointerInfo mpi = pointer.getMemberInfo(); + clang::QualType class_type = GetOrCreateType(mpi.ContainingType); + + return m_clang.getASTContext()->getMemberPointerType( + pointee_type, class_type.getTypePtr()); + } + + clang::QualType pointer_type; + if (pointer.getMode() == PointerMode::LValueReference) + pointer_type = + m_clang.getASTContext()->getLValueReferenceType(pointee_type); + else if (pointer.getMode() == PointerMode::RValueReference) + pointer_type = + m_clang.getASTContext()->getRValueReferenceType(pointee_type); + else + pointer_type = m_clang.getASTContext()->getPointerType(pointee_type); + + if ((pointer.getOptions() & PointerOptions::Const) != PointerOptions::None) + pointer_type.addConst(); + + if ((pointer.getOptions() & PointerOptions::Volatile) != PointerOptions::None) + pointer_type.addVolatile(); + + if ((pointer.getOptions() & PointerOptions::Restrict) != PointerOptions::None) + pointer_type.addRestrict(); + + return pointer_type; +} + +clang::QualType +PdbAstBuilder::CreateModifierType(const ModifierRecord &modifier) { + + clang::QualType unmodified_type = GetOrCreateType(modifier.ModifiedType); + + if ((modifier.Modifiers & ModifierOptions::Const) != ModifierOptions::None) + unmodified_type.addConst(); + if ((modifier.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None) + unmodified_type.addVolatile(); + + return unmodified_type; +} + +clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, + const TagRecord &record) { + clang::DeclContext *decl_context = nullptr; + std::string uname; + std::tie(decl_context, uname) = CreateDeclInfoForType(record, id.index); + + clang::TagTypeKind ttk = TranslateUdtKind(record); + lldb::AccessType access = + (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; + + ClangASTMetadata metadata; + metadata.SetUserID(toOpaqueUid(id)); + metadata.SetIsDynamicCXXType(false); + + CompilerType ct = + m_clang.CreateRecordType(decl_context, access, uname.c_str(), ttk, + lldb::eLanguageTypeC_plus_plus, &metadata); + + lldbassert(ct.IsValid()); + + 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. + clang::QualType result = + clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); + + ClangASTContext::SetHasExternalStorage(result.getAsOpaquePtr(), true); + return result; +} + +clang::Decl *PdbAstBuilder::TryGetDecl(PdbSymUid uid) const { + auto iter = m_uid_to_decl.find(toOpaqueUid(uid)); + if (iter != m_uid_to_decl.end()) + return iter->second; + return nullptr; +} + +clang::NamespaceDecl * +PdbAstBuilder::GetOrCreateNamespaceDecl(llvm::StringRef name, + clang::DeclContext &context) { + return m_clang.GetUniqueNamespaceDeclaration(name.str().c_str(), &context); +} + +clang::BlockDecl * +PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) { + if (clang::Decl *decl = TryGetDecl(block_id)) + return llvm::dyn_cast<clang::BlockDecl>(decl); + + clang::DeclContext *scope = GetParentDeclContext(block_id); + + clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope); + m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl}); + return block_decl; +} + +clang::VarDecl * +PdbAstBuilder::GetOrCreateLocalVariableDecl(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id) { + if (clang::Decl *decl = TryGetDecl(var_id)) + return llvm::dyn_cast<clang::VarDecl>(decl); + + clang::DeclContext *scope = GetOrCreateDeclContextForUid(scope_id); + + CVSymbol var = m_index.ReadSymbolRecord(var_id); + VariableInfo var_info = GetVariableNameInfo(var); + clang::QualType qt = GetOrCreateType(var_info.type); + + clang::VarDecl *var_decl = + m_clang.CreateVariableDeclaration(scope, var_info.name.str().c_str(), qt); + + m_uid_to_decl[toOpaqueUid(var_id)] = var_decl; + return var_decl; +} + +clang::QualType PdbAstBuilder::GetBasicType(lldb::BasicType type) { + CompilerType ct = m_clang.GetBasicType(type); + return clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); +} + +clang::QualType PdbAstBuilder::CreateType(PdbTypeSymId type) { + if (type.index.isSimple()) + return CreateSimpleType(type.index); + + CVType cvt = m_index.tpi().getType(type.index); + + if (cvt.kind() == LF_MODIFIER) { + ModifierRecord modifier; + llvm::cantFail( + TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier)); + return CreateModifierType(modifier); + } + + if (cvt.kind() == LF_POINTER) { + PointerRecord pointer; + llvm::cantFail( + TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer)); + return CreatePointerType(pointer); + } + + if (IsTagRecord(cvt)) { + CVTagRecord tag = CVTagRecord::create(cvt); + if (tag.kind() == CVTagRecord::Union) + return CreateRecordType(type.index, tag.asUnion()); + if (tag.kind() == CVTagRecord::Enum) + return CreateEnumType(type.index, tag.asEnum()); + return CreateRecordType(type.index, tag.asClass()); + } + + if (cvt.kind() == LF_ARRAY) { + ArrayRecord ar; + llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar)); + return CreateArrayType(ar); + } + + if (cvt.kind() == LF_PROCEDURE) { + ProcedureRecord pr; + llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr)); + return CreateProcedureType(pr); + } + + return {}; +} + +clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) { + lldb::user_id_t uid = toOpaqueUid(type); + auto iter = m_uid_to_type.find(uid); + if (iter != m_uid_to_type.end()) + return iter->second; + + PdbTypeSymId best_type = GetBestPossibleDecl(type, m_index.tpi()); + + clang::QualType qt; + if (best_type.index != type.index) { + // This is a forward decl. Call GetOrCreate on the full decl, then map the + // forward decl id to the full decl QualType. + clang::QualType qt = GetOrCreateType(best_type); + m_uid_to_type[toOpaqueUid(type)] = qt; + return qt; + } + + // This is either a full decl, or a forward decl with no matching full decl + // in the debug info. + qt = CreateType(type); + m_uid_to_type[toOpaqueUid(type)] = qt; + if (IsTagRecord(type, m_index.tpi())) { + clang::TagDecl *tag = qt->getAsTagDecl(); + lldbassert(m_decl_to_status.count(tag) == 0); + + DeclStatus &status = m_decl_to_status[tag]; + status.uid = uid; + status.resolved = false; + } + return qt; +} + +clang::FunctionDecl * +PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { + if (clang::Decl *decl = TryGetDecl(func_id)) + return llvm::dyn_cast<clang::FunctionDecl>(decl); + + clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id)); + + CVSymbol cvs = m_index.ReadSymbolRecord(func_id); + ProcSym proc(static_cast<SymbolRecordKind>(cvs.kind())); + llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(cvs, proc)); + + PdbTypeSymId type_id(proc.FunctionType); + clang::QualType qt = GetOrCreateType(type_id); + + clang::StorageClass storage = clang::SC_None; + if (proc.Kind == SymbolRecordKind::ProcSym) + storage = clang::SC_Static; + + const clang::FunctionProtoType *func_type = + llvm::dyn_cast<clang::FunctionProtoType>(qt); + + CompilerType func_ct = ToCompilerType(qt); + + clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( + parent, proc.Name.str().c_str(), func_ct, storage, false); + + lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); + m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; + + CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams()); + + return function_decl; +} + +void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, + clang::FunctionDecl &function_decl, + uint32_t param_count) { + CompilandIndexItem *cii = m_index.compilands().GetCompiland(func_id.modi); + CVSymbolArray scope = + cii->m_debug_stream.getSymbolArrayForScope(func_id.offset); + + auto begin = scope.begin(); + auto end = scope.end(); + std::vector<clang::ParmVarDecl *> params; + while (begin != end && param_count > 0) { + uint32_t record_offset = begin.offset(); + CVSymbol sym = *begin++; + + TypeIndex param_type; + llvm::StringRef param_name; + switch (sym.kind()) { + case S_REGREL32: { + RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); + cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); + param_type = reg.Type; + param_name = reg.Name; + break; + } + case S_REGISTER: { + RegisterSym reg(SymbolRecordKind::RegisterSym); + cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); + param_type = reg.Index; + param_name = reg.Name; + break; + } + case S_LOCAL: { + LocalSym local(SymbolRecordKind::LocalSym); + cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); + if ((local.Flags & LocalSymFlags::IsParameter) == LocalSymFlags::None) + continue; + param_type = local.Type; + param_name = local.Name; + break; + } + case S_BLOCK32: + // All parameters should come before the first block. If that isn't the + // case, then perhaps this is bad debug info that doesn't contain + // information about all parameters. + return; + default: + continue; + } + + PdbCompilandSymId param_uid(func_id.modi, record_offset); + clang::QualType qt = GetOrCreateType(param_type); + + CompilerType param_type_ct(&m_clang, qt.getAsOpaquePtr()); + clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( + &function_decl, param_name.str().c_str(), param_type_ct, + clang::SC_None); + lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); + + m_uid_to_decl[toOpaqueUid(param_uid)] = param; + params.push_back(param); + --param_count; + } + + if (!params.empty()) + m_clang.SetFunctionParameters(&function_decl, params.data(), params.size()); +} + +clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, + const EnumRecord &er) { + clang::DeclContext *decl_context = nullptr; + std::string uname; + std::tie(decl_context, uname) = CreateDeclInfoForType(er, id.index); + clang::QualType underlying_type = GetOrCreateType(er.UnderlyingType); + + Declaration declaration; + CompilerType enum_ct = m_clang.CreateEnumerationType( + uname.c_str(), decl_context, declaration, ToCompilerType(underlying_type), + er.isScoped()); + + ClangASTContext::StartTagDeclarationDefinition(enum_ct); + ClangASTContext::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); + + return clang::QualType::getFromOpaquePtr(enum_ct.GetOpaqueQualType()); +} + +clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) { + clang::QualType element_type = GetOrCreateType(ar.ElementType); + + uint64_t element_count = + ar.Size / GetSizeOfType({ar.ElementType}, m_index.tpi()); + + CompilerType array_ct = m_clang.CreateArrayType(ToCompilerType(element_type), + element_count, false); + return clang::QualType::getFromOpaquePtr(array_ct.GetOpaqueQualType()); +} + +clang::QualType +PdbAstBuilder::CreateProcedureType(const ProcedureRecord &proc) { + TpiStream &stream = m_index.tpi(); + CVType args_cvt = stream.getType(proc.ArgumentList); + ArgListRecord args; + llvm::cantFail( + TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args)); + + llvm::ArrayRef<TypeIndex> arg_indices = llvm::makeArrayRef(args.ArgIndices); + bool is_variadic = IsCVarArgsFunction(arg_indices); + if (is_variadic) + arg_indices = arg_indices.drop_back(); + + std::vector<CompilerType> arg_types; + arg_types.reserve(arg_indices.size()); + + for (TypeIndex arg_index : arg_indices) { + clang::QualType arg_type = GetOrCreateType(arg_index); + arg_types.push_back(ToCompilerType(arg_type)); + } + + clang::QualType return_type = GetOrCreateType(proc.ReturnType); + + llvm::Optional<clang::CallingConv> cc = + TranslateCallingConvention(proc.CallConv); + if (!cc) + return {}; + + CompilerType return_ct = ToCompilerType(return_type); + CompilerType func_sig_ast_type = m_clang.CreateFunctionType( + return_ct, arg_types.data(), arg_types.size(), is_variadic, 0, *cc); + + return clang::QualType::getFromOpaquePtr( + func_sig_ast_type.GetOpaqueQualType()); +} + +CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) { + return {&m_clang, &decl}; +} + +CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) { + return {&m_clang, qt.getAsOpaquePtr()}; +} + +CompilerDeclContext +PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) { + return {&m_clang, &context}; +} + +void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h new file mode 100644 index 00000000000..764d6ba190e --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h @@ -0,0 +1,129 @@ +//===-- PdbAstBuilder.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_PDBASTBUILDER_H +#define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_PDBASTBUILDER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" + +#include "lldb/Symbol/ClangASTImporter.h" + +#include "PdbIndex.h" +#include "PdbSymUid.h" + +namespace clang { +class TagDecl; +class DeclContext; +class Decl; +class QualType; +class FunctionDecl; +class NamespaceDecl; +} // namespace clang + +namespace llvm { +namespace codeview { +class ProcSym; +} +} // namespace llvm + +namespace lldb_private { +class ClangASTImporter; +class ObjectFile; + +namespace npdb { +class PdbIndex; +struct VariableInfo; + +struct DeclStatus { + DeclStatus() = default; + DeclStatus(lldb::user_id_t uid, bool resolved) + : uid(uid), resolved(resolved) {} + lldb::user_id_t uid = 0; + bool resolved = false; +}; + +class PdbAstBuilder { +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + PdbAstBuilder(ObjectFile &obj, PdbIndex &index); + + clang::DeclContext &GetTranslationUnitDecl(); + + clang::Decl *GetOrCreateDeclForUid(PdbSymUid uid); + clang::DeclContext *GetOrCreateDeclContextForUid(PdbSymUid uid); + clang::DeclContext *GetParentDeclContext(PdbSymUid uid); + + clang::NamespaceDecl *GetOrCreateNamespaceDecl(llvm::StringRef name, + clang::DeclContext &context); + clang::FunctionDecl *GetOrCreateFunctionDecl(PdbCompilandSymId func_id); + clang::BlockDecl *GetOrCreateBlockDecl(PdbCompilandSymId block_id); + clang::VarDecl *GetOrCreateLocalVariableDecl(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id); + + clang::QualType GetBasicType(lldb::BasicType type); + clang::QualType GetOrCreateType(PdbTypeSymId type); + + bool CompleteTagDecl(clang::TagDecl &tag); + bool CompleteType(clang::QualType qt); + + CompilerDecl ToCompilerDecl(clang::Decl &decl); + CompilerType ToCompilerType(clang::QualType qt); + CompilerDeclContext ToCompilerDeclContext(clang::DeclContext &context); + + ClangASTContext &clang() { return m_clang; } + ClangASTImporter &importer() { return m_importer; } + + void Dump(Stream &stream); + +private: + clang::Decl *TryGetDecl(PdbSymUid uid) const; + + using TypeIndex = llvm::codeview::TypeIndex; + + clang::QualType + CreatePointerType(const llvm::codeview::PointerRecord &pointer); + clang::QualType + CreateModifierType(const llvm::codeview::ModifierRecord &modifier); + clang::QualType CreateArrayType(const llvm::codeview::ArrayRecord &array); + clang::QualType CreateRecordType(PdbTypeSymId id, + const llvm::codeview::TagRecord &record); + clang::QualType CreateEnumType(PdbTypeSymId id, + const llvm::codeview::EnumRecord &record); + clang::QualType + CreateProcedureType(const llvm::codeview::ProcedureRecord &proc); + clang::QualType CreateType(PdbTypeSymId type); + + void CreateFunctionParameters(PdbCompilandSymId func_id, + clang::FunctionDecl &function_decl, + uint32_t param_count); + clang::Decl *GetOrCreateSymbolForId(PdbCompilandSymId id); + + void BuildParentMap(); + std::pair<clang::DeclContext *, std::string> + CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti); + clang::QualType CreateSimpleType(TypeIndex ti); + + PdbIndex &m_index; + ClangASTContext &m_clang; + + ClangASTImporter m_importer; + + llvm::DenseMap<TypeIndex, TypeIndex> m_parent_types; + llvm::DenseMap<clang::Decl *, DeclStatus> m_decl_to_status; + llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl; + llvm::DenseMap<lldb::user_id_t, clang::QualType> m_uid_to_type; +}; + +} // namespace npdb +} // namespace lldb_private + +#endif // lldb_Plugins_SymbolFile_PDB_SymbolFilePDB_h_ diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp index 4c19b61765b..daec5b7b07a 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// #include "PdbUtil.h" + +#include "DWARFLocationExpression.h" +#include "PdbIndex.h" #include "PdbSymUid.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" @@ -23,6 +26,27 @@ using namespace lldb_private::npdb; using namespace llvm::codeview; using namespace llvm::pdb; +static Variable::RangeList +MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range, + llvm::ArrayRef<LocalVariableAddrGap> gaps) { + lldb::addr_t start = + index.MakeVirtualAddress(range.ISectStart, range.OffsetStart); + lldb::addr_t end = start + range.Range; + + Variable::RangeList result; + while (!gaps.empty()) { + const LocalVariableAddrGap &gap = gaps.front(); + + lldb::addr_t size = gap.GapStartOffset - start; + result.Append(start, size); + start += gap.Range; + gaps = gaps.drop_front(); + } + + result.Append(start, end); + return result; +} + CVTagRecord CVTagRecord::create(CVType type) { assert(IsTagRecord(type) && "type is not a tag record!"); switch (type.kind()) { @@ -354,6 +378,17 @@ bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) { } } +bool lldb_private::npdb::IsClassStructUnion(llvm::codeview::CVType cvt) { + switch (cvt.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_UNION: + return true; + default: + return false; + } +} + bool lldb_private::npdb::IsForwardRefUdt(const PdbTypeSymId &id, TpiStream &tpi) { if (id.is_ipi || id.index.isSimple()) @@ -426,6 +461,90 @@ llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) { return name.substr(offset + 2); } +VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) { + VariableInfo result; + + if (sym.kind() == S_REGREL32) { + RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); + cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); + result.type = reg.Type; + result.name = reg.Name; + return result; + } + + if (sym.kind() == S_REGISTER) { + RegisterSym reg(SymbolRecordKind::RegisterSym); + cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); + result.type = reg.Index; + result.name = reg.Name; + return result; + } + + if (sym.kind() == S_LOCAL) { + LocalSym local(SymbolRecordKind::LocalSym); + cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); + result.type = local.Type; + result.name = local.Name; + return result; + } + + lldbassert(false && "Invalid variable record kind!"); + return {}; +} + +VariableInfo lldb_private::npdb::GetVariableLocationInfo( + PdbIndex &index, PdbCompilandSymId var_id, lldb::ModuleSP module) { + + CVSymbol sym = index.ReadSymbolRecord(var_id); + + VariableInfo result = GetVariableNameInfo(sym); + + if (sym.kind() == S_REGREL32) { + RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); + cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); + result.location = + MakeRegRelLocationExpression(reg.Register, reg.Offset, module); + result.ranges.emplace(); + return result; + } + + if (sym.kind() == S_REGISTER) { + RegisterSym reg(SymbolRecordKind::RegisterSym); + cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); + result.location = MakeEnregisteredLocationExpression(reg.Register, module); + result.ranges.emplace(); + return result; + } + + if (sym.kind() == S_LOCAL) { + LocalSym local(SymbolRecordKind::LocalSym); + cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); + + PdbCompilandSymId loc_specifier_id(var_id.modi, + var_id.offset + sym.RecordData.size()); + CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); + if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) { + DefRangeFramePointerRelSym loc( + SymbolRecordKind::DefRangeFramePointerRelSym); + cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>( + loc_specifier_cvs, loc)); + // FIXME: The register needs to come from the S_FRAMEPROC symbol. + result.location = + MakeRegRelLocationExpression(RegisterId::RSP, loc.Offset, module); + result.ranges = MakeRangeList(index, loc.Range, loc.Gaps); + } else { + // FIXME: Handle other kinds + llvm::APSInt value; + value = 42; + result.location = MakeConstantLocationExpression( + TypeIndex::Int32(), index.tpi(), value, module); + } + return result; + } + llvm_unreachable("Symbol is not a local variable!"); + return result; +} + lldb::BasicType lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) { switch (kind) { @@ -545,3 +664,72 @@ size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) { return 0; } } + +PdbTypeSymId lldb_private::npdb::GetBestPossibleDecl(PdbTypeSymId id, + TpiStream &tpi) { + if (id.index.isSimple()) + return id; + + CVType cvt = tpi.getType(id.index); + + // Only tag records have a best and a worst record. + if (!IsTagRecord(cvt)) + return id; + + // Tag records that are not forward decls are full decls, hence they are the + // best. + if (!IsForwardRefUdt(cvt)) + return id; + + return llvm::cantFail(tpi.findFullDeclForForwardRef(id.index)); +} + +template <typename RecordType> static size_t GetSizeOfTypeInternal(CVType cvt) { + RecordType record; + llvm::cantFail(TypeDeserializer::deserializeAs<RecordType>(cvt, record)); + return record.getSize(); +} + +size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id, + llvm::pdb::TpiStream &tpi) { + if (id.index.isSimple()) { + switch (id.index.getSimpleMode()) { + case SimpleTypeMode::Direct: + return GetTypeSizeForSimpleKind(id.index.getSimpleKind()); + case SimpleTypeMode::NearPointer32: + case SimpleTypeMode::FarPointer32: + return 4; + case SimpleTypeMode::NearPointer64: + return 8; + case SimpleTypeMode::NearPointer128: + return 16; + default: + break; + } + return 0; + } + + CVType cvt = tpi.getType(id.index); + switch (cvt.kind()) { + case LF_MODIFIER: + return GetSizeOfType({LookThroughModifierRecord(cvt)}, tpi); + case LF_ENUM: { + EnumRecord record; + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, record)); + return GetSizeOfType({record.UnderlyingType}, tpi); + } + case LF_POINTER: + return GetSizeOfTypeInternal<PointerRecord>(cvt); + case LF_ARRAY: + return GetSizeOfTypeInternal<ArrayRecord>(cvt); + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + return GetSizeOfTypeInternal<ClassRecord>(cvt); + case LF_UNION: + return GetSizeOfTypeInternal<UnionRecord>(cvt); + default: + break; + } + return 0; +} diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h index c01e419f58c..863f999a70f 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -10,13 +10,18 @@ #ifndef LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H #define LLDB_PLUGINS_SYMBOLFILENATIVEPDB_PDBUTIL_H +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/Variable.h" #include "lldb/lldb-enumerations.h" +#include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "PdbSymUid.h" + #include <tuple> #include <utility> @@ -29,7 +34,7 @@ class TpiStream; namespace lldb_private { namespace npdb { -struct PdbTypeSymId; +class PdbIndex; struct CVTagRecord { enum Kind { Class, Struct, Union, Enum }; @@ -88,6 +93,13 @@ struct SegmentOffsetLength { uint32_t length = 0; }; +struct VariableInfo { + llvm::StringRef name; + llvm::codeview::TypeIndex type; + llvm::Optional<DWARFExpression> location; + llvm::Optional<Variable::RangeList> ranges; +}; + llvm::pdb::PDB_SymType CVSymToPDBSym(llvm::codeview::SymbolKind kind); llvm::pdb::PDB_SymType CVTypeToPDBType(llvm::codeview::TypeLeafKind kind); @@ -109,6 +121,7 @@ inline bool IsValidRecord(const llvm::codeview::ProcRefSym &sym) { bool IsForwardRefUdt(llvm::codeview::CVType cvt); bool IsTagRecord(llvm::codeview::CVType cvt); +bool IsClassStructUnion(llvm::codeview::CVType cvt); bool IsForwardRefUdt(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi); bool IsTagRecord(const PdbTypeSymId &id, llvm::pdb::TpiStream &tpi); @@ -120,10 +133,18 @@ LookThroughModifierRecord(llvm::codeview::CVType modifier); llvm::StringRef DropNameScope(llvm::StringRef name); +VariableInfo GetVariableNameInfo(llvm::codeview::CVSymbol symbol); +VariableInfo GetVariableLocationInfo(PdbIndex &index, PdbCompilandSymId var_id, + lldb::ModuleSP module); + size_t GetTypeSizeForSimpleKind(llvm::codeview::SimpleTypeKind kind); lldb::BasicType GetCompilerTypeForSimpleKind(llvm::codeview::SimpleTypeKind kind); +PdbTypeSymId GetBestPossibleDecl(PdbTypeSymId id, llvm::pdb::TpiStream &tpi); + +size_t GetSizeOfType(PdbTypeSymId id, llvm::pdb::TpiStream &tpi); + } // namespace npdb } // namespace lldb_private diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index c7882e981f0..fa168899802 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -56,6 +56,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "DWARFLocationExpression.h" +#include "PdbAstBuilder.h" #include "PdbSymUid.h" #include "PdbUtil.h" #include "UdtRecordCompleter.h" @@ -66,15 +67,6 @@ using namespace npdb; using namespace llvm::codeview; using namespace llvm::pdb; -namespace { -struct VariableInfo { - llvm::StringRef name; - TypeIndex type; - llvm::Optional<DWARFExpression> location; - llvm::Optional<Variable::RangeList> ranges; -}; -} // namespace - static lldb::LanguageType TranslateLanguage(PDB_Lang lang) { switch (lang) { case PDB_Lang::Cpp: @@ -171,30 +163,6 @@ 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 llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) { switch (kind) { case SimpleTypeKind::Boolean128: @@ -273,144 +241,6 @@ static bool IsClassRecord(TypeLeafKind kind) { } } -static bool IsCVarArgsFunction(llvm::ArrayRef<TypeIndex> args) { - if (args.empty()) - return false; - return args.back() == TypeIndex::None(); -} - -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; - } -} - -static llvm::Optional<clang::CallingConv> -TranslateCallingConvention(llvm::codeview::CallingConvention conv) { - using CC = llvm::codeview::CallingConvention; - switch (conv) { - - case CC::NearC: - case CC::FarC: - return clang::CallingConv::CC_C; - case CC::NearPascal: - case CC::FarPascal: - return clang::CallingConv::CC_X86Pascal; - case CC::NearFast: - case CC::FarFast: - return clang::CallingConv::CC_X86FastCall; - case CC::NearStdCall: - case CC::FarStdCall: - return clang::CallingConv::CC_X86StdCall; - case CC::ThisCall: - return clang::CallingConv::CC_X86ThisCall; - case CC::NearVector: - return clang::CallingConv::CC_X86VectorCall; - default: - return llvm::None; - } -} - -static Variable::RangeList -MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range, - llvm::ArrayRef<LocalVariableAddrGap> gaps) { - lldb::addr_t start = - index.MakeVirtualAddress(range.ISectStart, range.OffsetStart); - lldb::addr_t end = start + range.Range; - - Variable::RangeList result; - while (!gaps.empty()) { - const LocalVariableAddrGap &gap = gaps.front(); - - lldb::addr_t size = gap.GapStartOffset - start; - result.Append(start, size); - start += gap.Range; - gaps = gaps.drop_front(); - } - - result.Append(start, end); - return result; -} - -static VariableInfo GetVariableInformation(PdbIndex &index, - PdbCompilandSymId var_id, - ModuleSP module, - bool get_location_info) { - VariableInfo result; - CVSymbol sym = index.ReadSymbolRecord(var_id); - - if (sym.kind() == S_REGREL32) { - RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); - cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); - result.type = reg.Type; - result.name = reg.Name; - if (get_location_info) { - result.location = - MakeRegRelLocationExpression(reg.Register, reg.Offset, module); - result.ranges.emplace(); - } - return result; - } - - if (sym.kind() == S_REGISTER) { - RegisterSym reg(SymbolRecordKind::RegisterSym); - cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); - result.type = reg.Index; - result.name = reg.Name; - if (get_location_info) { - result.location = - MakeEnregisteredLocationExpression(reg.Register, module); - result.ranges.emplace(); - } - return result; - } - - if (sym.kind() == S_LOCAL) { - LocalSym local(SymbolRecordKind::LocalSym); - cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); - result.type = local.Type; - result.name = local.Name; - - if (!get_location_info) - return result; - - PdbCompilandSymId loc_specifier_id(var_id.modi, - var_id.offset + sym.RecordData.size()); - CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); - if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) { - DefRangeFramePointerRelSym loc( - SymbolRecordKind::DefRangeFramePointerRelSym); - cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>( - loc_specifier_cvs, loc)); - // FIXME: The register needs to come from the S_FRAMEPROC symbol. - result.location = - MakeRegRelLocationExpression(RegisterId::RSP, loc.Offset, module); - result.ranges = MakeRangeList(index, loc.Range, loc.Gaps); - } else { - // FIXME: Handle other kinds - llvm::APSInt value; - value = 42; - result.location = MakeConstantLocationExpression( - TypeIndex::Int32(), index.tpi(), value, module); - } - return result; - } - llvm_unreachable("Symbol is not a local variable!"); - return result; -} - void SymbolFileNativePDB::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, @@ -489,117 +319,12 @@ void SymbolFileNativePDB::InitializeObject() { 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>(); - - PreprocessTpiStream(); - lldbassert(m_clang); -} - -static llvm::Optional<CVTagRecord> -GetNestedTagRecord(const NestedTypeRecord &Record, const CVTagRecord &parent, - TpiStream &tpi) { - // An LF_NESTTYPE is essentially a nested typedef / using declaration, but it - // is also used to indicate the primary definition of a nested class. That is - // to say, if you have: - // struct A { - // struct B {}; - // using C = B; - // }; - // Then in the debug info, this will appear as: - // LF_STRUCTURE `A::B` [type index = N] - // LF_STRUCTURE `A` - // LF_NESTTYPE [name = `B`, index = N] - // LF_NESTTYPE [name = `C`, index = N] - // In order to accurately reconstruct the decl context hierarchy, we need to - // know which ones are actual definitions and which ones are just aliases. - - // If it's a simple type, then this is something like `using foo = int`. - if (Record.Type.isSimple()) - return llvm::None; - - CVType cvt = tpi.getType(Record.Type); - - if (!IsTagRecord(cvt)) - return llvm::None; - - // If it's an inner definition, then treat whatever name we have here as a - // single component of a mangled name. So we can inject it into the parent's - // mangled name to see if it matches. - CVTagRecord child = CVTagRecord::create(cvt); - std::string qname = parent.asTag().getUniqueName(); - if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4) - return llvm::None; - - // qname[3] is the tag type identifier (struct, class, union, etc). Since the - // inner tag type is not necessarily the same as the outer tag type, re-write - // it to match the inner tag type. - qname[3] = child.asTag().getUniqueName()[3]; - std::string piece = Record.Name; - piece.push_back('@'); - qname.insert(4, std::move(piece)); - if (qname != child.asTag().UniqueName) - return llvm::None; - - return std::move(child); -} - -void SymbolFileNativePDB::PreprocessTpiStream() { - LazyRandomTypeCollection &types = m_index->tpi().typeCollection(); - - for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) { - CVType type = types.getType(*ti); - if (!IsTagRecord(type)) - continue; - - CVTagRecord tag = CVTagRecord::create(type); - // We're looking for LF_NESTTYPE records in the field list, so ignore - // forward references (no field list), and anything without a nested class - // (since there won't be any LF_NESTTYPE records). - if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass()) - continue; - - struct ProcessTpiStream : public TypeVisitorCallbacks { - ProcessTpiStream(PdbIndex &index, TypeIndex parent, - const CVTagRecord &parent_cvt, - llvm::DenseMap<TypeIndex, TypeIndex> &parents) - : index(index), parents(parents), parent(parent), - parent_cvt(parent_cvt) {} - - PdbIndex &index; - llvm::DenseMap<TypeIndex, TypeIndex> &parents; - TypeIndex parent; - const CVTagRecord &parent_cvt; - - llvm::Error visitKnownMember(CVMemberRecord &CVR, - NestedTypeRecord &Record) override { - llvm::Optional<CVTagRecord> tag = - GetNestedTagRecord(Record, parent_cvt, index.tpi()); - if (!tag) - return llvm::ErrorSuccess(); - - parents[Record.Type] = parent; - if (!tag->asTag().isForwardRef()) - return llvm::ErrorSuccess(); - - llvm::Expected<TypeIndex> full_decl = - index.tpi().findFullDeclForForwardRef(Record.Type); - if (!full_decl) { - llvm::consumeError(full_decl.takeError()); - return llvm::ErrorSuccess(); - } - parents[*full_decl] = parent; - return llvm::ErrorSuccess(); - } - }; + TypeSystem *ts = m_obj_file->GetModule()->GetTypeSystemForLanguage( + lldb::eLanguageTypeC_plus_plus); + if (ts) + ts->SetSymbolFile(this); - CVType field_list = m_index->tpi().getType(tag.asTag().FieldList); - ProcessTpiStream process(*m_index, *ti, tag, m_parent_types); - llvm::Error error = visitMemberRecordStream(field_list.data(), process); - if (error) - llvm::consumeError(std::move(error)); - } + m_ast = llvm::make_unique<PdbAstBuilder>(*m_obj_file, *m_index); } uint32_t SymbolFileNativePDB::GetNumCompileUnits() { @@ -620,7 +345,6 @@ uint32_t SymbolFileNativePDB::GetNumCompileUnits() { Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) { CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi); CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset); - clang::DeclContext *parent_decl_ctx = m_clang->GetTranslationUnitDecl(); if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) { // This is a function. It must be global. Creating the Function entry for @@ -639,18 +363,13 @@ Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) { lldbassert(block.Parent != 0); PdbCompilandSymId parent_id(block_id.modi, block.Parent); Block &parent_block = GetOrCreateBlock(parent_id); - lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id); BlockSP child_block = std::make_shared<Block>(opaque_block_uid); parent_block.AddChild(child_block); - CompilerDeclContext cdc = GetDeclContextForUID(parent_block.GetID()); - parent_decl_ctx = - static_cast<clang::DeclContext *>(cdc.GetOpaqueDeclContext()); - clang::BlockDecl *block_decl = - m_clang->CreateBlockDeclaration(parent_decl_ctx); + + m_ast->GetOrCreateBlockDecl(block_id); m_blocks.insert({opaque_block_uid, child_block}); - m_uid_to_decl.insert({opaque_block_uid, block_decl}); return *child_block; } @@ -685,73 +404,7 @@ lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id, comp_unit.AddFunction(func_sp); - user_id_t opaque_func_uid = toOpaqueUid(func_id); - - clang::StorageClass storage = clang::SC_None; - if (sym_record.kind() == S_LPROC32) - storage = clang::SC_Static; - - // The function signature only tells us the number of types of arguments, but - // not the names. So we need to iterate the symbol stream looking for the - // corresponding symbol records to properly construct the AST. - CVType sig_cvt; - ProcedureRecord sig_record; - - sig_cvt = m_index->tpi().getType(proc.FunctionType); - if (sig_cvt.kind() != LF_PROCEDURE) - return func_sp; - cantFail( - TypeDeserializer::deserializeAs<ProcedureRecord>(sig_cvt, sig_record)); - - CompilerDeclContext context = GetDeclContextContainingUID(opaque_func_uid); - - clang::DeclContext *decl_context = - static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext()); - clang::FunctionDecl *function_decl = m_clang->CreateFunctionDeclaration( - decl_context, proc.Name.str().c_str(), - func_type->GetForwardCompilerType(), storage, false); - - lldbassert(m_uid_to_decl.count(opaque_func_uid) == 0); - m_uid_to_decl[opaque_func_uid] = function_decl; - - CVSymbolArray scope = limitSymbolArrayToScope( - cci->m_debug_stream.getSymbolArray(), func_id.offset); - - uint32_t params_remaining = sig_record.getParameterCount(); - auto begin = scope.begin(); - auto end = scope.end(); - std::vector<clang::ParmVarDecl *> params; - while (begin != end && params_remaining > 0) { - CVSymbol sym = *begin; - switch (sym.kind()) { - case S_REGREL32: - case S_REGISTER: - case S_LOCAL: - break; - case S_BLOCK32: - params_remaining = 0; - continue; - default: - ++begin; - continue; - } - PdbCompilandSymId param_uid(func_id.modi, begin.offset()); - VariableInfo var_info = GetVariableInformation( - *m_index, param_uid, GetObjectFile()->GetModule(), false); - - TypeSP type_sp = GetOrCreateType(var_info.type); - clang::ParmVarDecl *param = m_clang->CreateParameterDeclaration( - function_decl, var_info.name.str().c_str(), - type_sp->GetForwardCompilerType(), clang::SC_None); - lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); - - m_uid_to_decl[toOpaqueUid(param_uid)] = param; - params.push_back(param); - --params_remaining; - ++begin; - } - if (!params.empty()) - m_clang->SetFunctionParameters(function_decl, params.data(), params.size()); + m_ast->GetOrCreateFunctionDecl(func_id); return func_sp; } @@ -780,76 +433,48 @@ SymbolFileNativePDB::CreateCompileUnit(const CompilandIndexItem &cci) { } lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id, - const ModifierRecord &mr) { + const ModifierRecord &mr, + CompilerType ct) { 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>(toOpaqueUid(type_id), m_clang->GetSymbolFile(), - ConstString(name), t->GetByteSize(), nullptr, + lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType); + + return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(name), + modified_type->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull); } -lldb::TypeSP SymbolFileNativePDB::CreatePointerType( - PdbTypeSymId type_id, const llvm::codeview::PointerRecord &pr) { +lldb::TypeSP +SymbolFileNativePDB::CreatePointerType(PdbTypeSymId type_id, + const llvm::codeview::PointerRecord &pr, + CompilerType ct) { TypeSP pointee = GetOrCreateType(pr.ReferentType); if (!pointee) return nullptr; - 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>( - toOpaqueUid(type_id), m_clang->GetSymbolFile(), ConstString(), - pr.getSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, - Type::eResolveStateFull); + GetOrCreateType(mpi.ContainingType); } - 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>(toOpaqueUid(type_id), m_clang->GetSymbolFile(), - ConstString(), pr.getSize(), nullptr, - LLDB_INVALID_UID, Type::eEncodingIsUID, decl, - pointer_ct, Type::eResolveStateFull); + Declaration decl; + return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(), + pr.getSize(), nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, ct, + Type::eResolveStateFull); } -lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) { +lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti, + CompilerType ct) { uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false)); if (ti == TypeIndex::NullptrT()) { - CompilerType ct = m_clang->GetBasicType(eBasicTypeNullPtr); Declaration decl; return std::make_shared<Type>( uid, this, ConstString("std::nullptr_t"), 0, nullptr, LLDB_INVALID_UID, @@ -858,8 +483,6 @@ lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) { if (ti.getSimpleMode() != SimpleTypeMode::Direct) { TypeSP direct_sp = GetOrCreateType(ti.makeDirect()); - CompilerType ct = direct_sp->GetFullCompilerType(); - ct = ct.GetPointerType(); uint32_t pointer_size = 0; switch (ti.getSimpleMode()) { case SimpleTypeMode::FarPointer32: @@ -874,253 +497,101 @@ lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) { return nullptr; } Declaration decl; - return std::make_shared<Type>(uid, m_clang->GetSymbolFile(), ConstString(), - pointer_size, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, decl, ct, - Type::eResolveStateFull); + return std::make_shared<Type>( + uid, this, ConstString(), pointer_size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, ct, Type::eResolveStateFull); } if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated) return nullptr; - lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind()); - if (bt == lldb::eBasicTypeInvalid) - return nullptr; - 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, m_clang->GetSymbolFile(), - ConstString(type_name), size, nullptr, - LLDB_INVALID_UID, Type::eEncodingIsUID, decl, - ct, Type::eResolveStateFull); + return std::make_shared<Type>(uid, this, ConstString(type_name), size, + nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, + decl, ct, Type::eResolveStateFull); } -static std::string RenderDemanglerNode(llvm::ms_demangle::Node *n) { - OutputStream OS; - initializeOutputStream(nullptr, nullptr, OS, 1024); - n->output(OS, llvm::ms_demangle::OF_Default); - OS << '\0'; - return {OS.getBuffer()}; -} - -static bool -AnyScopesHaveTemplateParams(llvm::ArrayRef<llvm::ms_demangle::Node *> scopes) { - for (llvm::ms_demangle::Node *n : scopes) { - auto *idn = static_cast<llvm::ms_demangle::IdentifierNode *>(n); - if (idn->TemplateParams) - return true; - } - return false; -} - -std::pair<clang::DeclContext *, std::string> -SymbolFileNativePDB::CreateDeclInfoForType(const TagRecord &record, - TypeIndex ti) { - // FIXME: Move this to GetDeclContextContainingUID. - +static std::string GetUnqualifiedTypeName(const TagRecord &record) { llvm::ms_demangle::Demangler demangler; StringView sv(record.UniqueName.begin(), record.UniqueName.size()); llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv); llvm::ms_demangle::IdentifierNode *idn = ttn->QualifiedName->getUnqualifiedIdentifier(); - std::string uname = RenderDemanglerNode(idn); - - llvm::ms_demangle::NodeArrayNode *name_components = - ttn->QualifiedName->Components; - llvm::ArrayRef<llvm::ms_demangle::Node *> scopes(name_components->Nodes, - name_components->Count - 1); - - clang::DeclContext *context = m_clang->GetTranslationUnitDecl(); - - // If this type doesn't have a parent type in the debug info, then the best we - // can do is to say that it's either a series of namespaces (if the scope is - // non-empty), or the translation unit (if the scope is empty). - auto parent_iter = m_parent_types.find(ti); - if (parent_iter == m_parent_types.end()) { - if (scopes.empty()) - return {context, uname}; - - // If there is no parent in the debug info, but some of the scopes have - // template params, then this is a case of bad debug info. See, for - // example, llvm.org/pr39607. We don't want to create an ambiguity between - // a NamespaceDecl and a CXXRecordDecl, so instead we create a class at - // global scope with the fully qualified name. - if (AnyScopesHaveTemplateParams(scopes)) - return {context, record.Name}; - - for (llvm::ms_demangle::Node *scope : scopes) { - auto *nii = static_cast<llvm::ms_demangle::NamedIdentifierNode *>(scope); - std::string str = RenderDemanglerNode(nii); - context = m_clang->GetUniqueNamespaceDeclaration(str.c_str(), context); - } - return {context, uname}; - } - - // Otherwise, all we need to do is get the parent type of this type and - // recurse into our lazy type creation / AST reconstruction logic to get an - // LLDB TypeSP for the parent. This will cause the AST to automatically get - // the right DeclContext created for any parent. - TypeSP parent = GetOrCreateType(parent_iter->second); - if (!parent) - return {context, uname}; - CompilerType parent_ct = parent->GetForwardCompilerType(); - clang::QualType qt = ClangUtil::GetCanonicalQualType(parent_ct); - context = clang::TagDecl::castToDeclContext(qt->getAsTagDecl()); - return {context, uname}; + return idn->toString(); } -lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion( - PdbTypeSymId type_id, const llvm::codeview::TagRecord &record, size_t size, - clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) { - - clang::DeclContext *decl_context = nullptr; - std::string uname; - std::tie(decl_context, uname) = CreateDeclInfoForType(record, type_id.index); - - lldb::AccessType access = - (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; +lldb::TypeSP +SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id, + const TagRecord &record, + size_t size, CompilerType ct) { - ClangASTMetadata metadata; - metadata.SetUserID(toOpaqueUid(type_id)); - metadata.SetIsDynamicCXXType(false); - - CompilerType ct = - m_clang->CreateRecordType(decl_context, access, uname.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); + std::string uname = GetUnqualifiedTypeName(record); // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE. Declaration decl; - return std::make_shared<Type>(toOpaqueUid(type_id), m_clang->GetSymbolFile(), - ConstString(uname), size, nullptr, - LLDB_INVALID_UID, Type::eEncodingIsUID, decl, - ct, Type::eResolveStateForward); + return std::make_shared<Type>(toOpaqueUid(type_id), this, ConstString(uname), + size, nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, decl, ct, + Type::eResolveStateForward); } lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, - const ClassRecord &cr) { - clang::TagTypeKind ttk = TranslateUdtKind(cr); - - clang::MSInheritanceAttr::Spelling inheritance = - GetMSInheritance(m_index->tpi().typeCollection(), cr); - return CreateClassStructUnion(type_id, cr, cr.getSize(), ttk, inheritance); + const ClassRecord &cr, + CompilerType ct) { + return CreateClassStructUnion(type_id, cr, cr.getSize(), ct); } lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, - const UnionRecord &ur) { - return CreateClassStructUnion( - type_id, ur, ur.getSize(), clang::TTK_Union, - clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance); + const UnionRecord &ur, + CompilerType ct) { + return CreateClassStructUnion(type_id, ur, ur.getSize(), ct); } lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, - const EnumRecord &er) { - clang::DeclContext *decl_context = nullptr; - std::string uname; - std::tie(decl_context, uname) = CreateDeclInfoForType(er, type_id.index); + const EnumRecord &er, + CompilerType ct) { + std::string uname = GetUnqualifiedTypeName(er); Declaration decl; TypeSP underlying_type = GetOrCreateType(er.UnderlyingType); - CompilerType enum_ct = m_clang->CreateEnumerationType( - uname.c_str(), decl_context, decl, underlying_type->GetFullCompilerType(), - er.isScoped()); - ClangASTContext::StartTagDeclarationDefinition(enum_ct); - ClangASTContext::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); - - // 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>( - toOpaqueUid(type_id), m_clang->GetSymbolFile(), ConstString(uname), + toOpaqueUid(type_id), this, ConstString(uname), underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID, - lldb_private::Type::eEncodingIsUID, decl, enum_ct, + lldb_private::Type::eEncodingIsUID, decl, ct, lldb_private::Type::eResolveStateForward); } TypeSP SymbolFileNativePDB::CreateArrayType(PdbTypeSymId type_id, - const ArrayRecord &ar) { + const ArrayRecord &ar, + CompilerType ct) { TypeSP element_type = GetOrCreateType(ar.ElementType); - uint64_t element_count = ar.Size / element_type->GetByteSize(); - - CompilerType element_ct = element_type->GetFullCompilerType(); - - CompilerType array_ct = - m_clang->CreateArrayType(element_ct, element_count, false); Declaration decl; TypeSP array_sp = std::make_shared<lldb_private::Type>( - toOpaqueUid(type_id), m_clang->GetSymbolFile(), ConstString(), ar.Size, - nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, - array_ct, lldb_private::Type::eResolveStateFull); + toOpaqueUid(type_id), this, ConstString(), ar.Size, nullptr, + LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, + lldb_private::Type::eResolveStateFull); array_sp->SetEncodingType(element_type.get()); return array_sp; } TypeSP SymbolFileNativePDB::CreateProcedureType(PdbTypeSymId type_id, - const ProcedureRecord &pr) { - TpiStream &stream = m_index->tpi(); - CVType args_cvt = stream.getType(pr.ArgumentList); - ArgListRecord args; - llvm::cantFail( - TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args)); - - llvm::ArrayRef<TypeIndex> arg_indices = llvm::makeArrayRef(args.ArgIndices); - bool is_variadic = IsCVarArgsFunction(arg_indices); - if (is_variadic) - arg_indices = arg_indices.drop_back(); - - std::vector<CompilerType> arg_list; - arg_list.reserve(arg_list.size()); - - for (TypeIndex arg_index : arg_indices) { - TypeSP arg_sp = GetOrCreateType(arg_index); - if (!arg_sp) - return nullptr; - arg_list.push_back(arg_sp->GetFullCompilerType()); - } - - TypeSP return_type_sp = GetOrCreateType(pr.ReturnType); - if (!return_type_sp) - return nullptr; - - llvm::Optional<clang::CallingConv> cc = - TranslateCallingConvention(pr.CallConv); - if (!cc) - return nullptr; - - CompilerType return_ct = return_type_sp->GetFullCompilerType(); - CompilerType func_sig_ast_type = m_clang->CreateFunctionType( - return_ct, arg_list.data(), arg_list.size(), is_variadic, 0, *cc); - + const ProcedureRecord &pr, + CompilerType ct) { Declaration decl; return std::make_shared<lldb_private::Type>( toOpaqueUid(type_id), this, ConstString(), 0, nullptr, LLDB_INVALID_UID, - lldb_private::Type::eEncodingIsUID, decl, func_sig_ast_type, + lldb_private::Type::eEncodingIsUID, decl, ct, lldb_private::Type::eResolveStateFull); } -TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id) { +TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id, CompilerType ct) { if (type_id.index.isSimple()) - return CreateSimpleType(type_id.index); + return CreateSimpleType(type_id.index, ct); TpiStream &stream = type_id.is_ipi ? m_index->ipi() : m_index->tpi(); CVType cvt = stream.getType(type_id.index); @@ -1129,44 +600,44 @@ TypeSP SymbolFileNativePDB::CreateType(PdbTypeSymId type_id) { ModifierRecord modifier; llvm::cantFail( TypeDeserializer::deserializeAs<ModifierRecord>(cvt, modifier)); - return CreateModifierType(type_id, modifier); + return CreateModifierType(type_id, modifier, ct); } if (cvt.kind() == LF_POINTER) { PointerRecord pointer; llvm::cantFail( TypeDeserializer::deserializeAs<PointerRecord>(cvt, pointer)); - return CreatePointerType(type_id, pointer); + return CreatePointerType(type_id, pointer, ct); } if (IsClassRecord(cvt.kind())) { ClassRecord cr; llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, cr)); - return CreateTagType(type_id, cr); + return CreateTagType(type_id, cr, ct); } if (cvt.kind() == LF_ENUM) { EnumRecord er; llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er)); - return CreateTagType(type_id, er); + return CreateTagType(type_id, er, ct); } if (cvt.kind() == LF_UNION) { UnionRecord ur; llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, ur)); - return CreateTagType(type_id, ur); + return CreateTagType(type_id, ur, ct); } if (cvt.kind() == LF_ARRAY) { ArrayRecord ar; llvm::cantFail(TypeDeserializer::deserializeAs<ArrayRecord>(cvt, ar)); - return CreateArrayType(type_id, ar); + return CreateArrayType(type_id, ar, ct); } if (cvt.kind() == LF_PROCEDURE) { ProcedureRecord pr; llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr)); - return CreateProcedureType(type_id, pr); + return CreateProcedureType(type_id, pr, ct); } return nullptr; @@ -1200,7 +671,10 @@ TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) { } PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id; - TypeSP result = CreateType(best_decl_id); + + clang::QualType qt = m_ast->GetOrCreateType(best_decl_id); + + TypeSP result = CreateType(best_decl_id, m_ast->ToCompilerType(qt)); if (!result) return nullptr; @@ -1211,15 +685,6 @@ TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) { if (full_decl_uid) m_types[toOpaqueUid(type_id)] = result; - if (IsTagRecord(best_decl_id, m_index->tpi())) { - clang::TagDecl *record_decl = - m_clang->GetAsTagDecl(result->GetForwardCompilerType()); - lldbassert(record_decl); - - m_uid_to_decl[best_uid] = record_decl; - m_decl_to_status[record_decl] = - DeclStatus(best_uid, Type::eResolveStateForward); - } return result; } @@ -1631,11 +1096,7 @@ size_t SymbolFileNativePDB::ParseFunctionBlocks(const SymbolContext &sc) { return 1; } -void SymbolFileNativePDB::DumpClangAST(Stream &s) { - if (!m_clang) - return; - m_clang->Dump(s); -} +void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); } uint32_t SymbolFileNativePDB::FindGlobalVariables( const ConstString &name, const CompilerDeclContext *parent_decl_ctx, @@ -1764,8 +1225,7 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param) { ModuleSP module = GetObjectFile()->GetModule(); - VariableInfo var_info = - GetVariableInformation(*m_index, var_id, module, true); + VariableInfo var_info = GetVariableLocationInfo(*m_index, var_id, module); CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi); CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii); @@ -1782,20 +1242,8 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false, false, false); - CompilerDeclContext cdc = GetDeclContextForUID(toOpaqueUid(scope_id)); - clang::DeclContext *decl_ctx = - static_cast<clang::DeclContext *>(cdc.GetOpaqueDeclContext()); - - // Parameter info should have already been added to the AST. - if (!is_param) { - clang::QualType qt = - ClangUtil::GetCanonicalQualType(type_sp->GetForwardCompilerType()); - - clang::VarDecl *var_decl = - m_clang->CreateVariableDeclaration(decl_ctx, name.c_str(), qt); - lldbassert(m_uid_to_decl.count(toOpaqueUid(var_id)) == 0); - m_uid_to_decl[toOpaqueUid(var_id)] = var_decl; - } + if (!is_param) + m_ast->GetOrCreateLocalVariableDecl(scope_id, var_id); m_local_variables[toOpaqueUid(var_id)] = var_sp; return var_sp; @@ -1919,44 +1367,25 @@ size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) { } CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) { - auto iter = m_uid_to_decl.find(uid); - if (iter == m_uid_to_decl.end()) - return CompilerDecl(); + clang::Decl *decl = m_ast->GetOrCreateDeclForUid(PdbSymUid(uid)); - return {m_clang, iter->second}; + return m_ast->ToCompilerDecl(*decl); } CompilerDeclContext SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) { - CompilerDecl compiler_decl = GetDeclForUID(uid); - clang::Decl *decl = static_cast<clang::Decl *>(compiler_decl.GetOpaqueDecl()); - return {m_clang, clang::Decl::castToDeclContext(decl)}; + clang::DeclContext *context = + m_ast->GetOrCreateDeclContextForUid(PdbSymUid(uid)); + if (!context) + return {}; + + return m_ast->ToCompilerDeclContext(*context); } CompilerDeclContext SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { - // FIXME: This should look up the uid, decide if it's a symbol or a type, and - // depending which it is, find the appropriate DeclContext. Possibilities: - // For classes and typedefs: - // * Function - // * Namespace - // * Global - // * Block - // * Class - // For field list members: - // * Class - // For variables: - // * Function - // * Namespace - // * Global - // * Block - // For functions: - // * Namespace - // * Global - // * Class - // - // It is an error to call this function with a uid for any other symbol type. - return {m_clang, m_clang->GetTranslationUnitDecl()}; + clang::DeclContext *context = m_ast->GetParentDeclContext(PdbSymUid(uid)); + return m_ast->ToCompilerDeclContext(*context); } Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) { @@ -1987,73 +1416,10 @@ SymbolFileNativePDB::GetDynamicArrayInfoForUID( 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; + clang::QualType qt = + clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType()); - PdbTypeSymId type_id = PdbSymUid(status.uid).asTypeSym(); - - lldbassert(IsTagRecord(type_id, m_index->tpi())); - - 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(status.uid); - lldbassert(types_iter != m_types.end()); - - if (cvt.kind() == LF_MODIFIER) { - TypeIndex unmodified_type = LookThroughModifierRecord(cvt); - cvt = m_index->tpi().getType(unmodified_type); - // LF_MODIFIERS usually point to forward decls, so this is the one case - // where we won't have been able to resolve a forward decl to a full decl - // earlier on. So we need to do that now. - if (IsForwardRefUdt(cvt)) { - llvm::Expected<TypeIndex> expected_full_ti = - m_index->tpi().findFullDeclForForwardRef(unmodified_type); - if (!expected_full_ti) { - llvm::consumeError(expected_full_ti.takeError()); - return false; - } - cvt = m_index->tpi().getType(*expected_full_ti); - lldbassert(!IsForwardRefUdt(cvt)); - unmodified_type = *expected_full_ti; - } - type_id = PdbTypeSymId(unmodified_type, false); - } - 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(type_id, 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; + return m_ast->CompleteType(qt); } size_t SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index d8c1a0daa61..39abb9ca633 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -39,14 +39,7 @@ namespace lldb_private { class ClangASTImporter; namespace npdb { - -struct DeclStatus { - DeclStatus() = default; - DeclStatus(lldb::user_id_t uid, Type::ResolveStateTag status) - : uid(uid), status(status) {} - lldb::user_id_t uid = 0; - Type::ResolveStateTag status = Type::eResolveStateForward; -}; +class PdbAstBuilder; class SymbolFileNativePDB : public SymbolFile { friend class UdtRecordCompleter; @@ -158,40 +151,38 @@ public: llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); } const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); } - ClangASTContext &GetASTContext() { return *m_clang; } - ClangASTImporter &GetASTImporter() { return *m_importer; } - void DumpClangAST(Stream &s) override; private: - std::pair<clang::DeclContext *, std::string> - CreateDeclInfoForType(const llvm::codeview::TagRecord &record, - llvm::codeview::TypeIndex ti); - void PreprocessTpiStream(); size_t FindTypesByName(llvm::StringRef name, uint32_t max_matches, TypeMap &types); lldb::TypeSP CreateModifierType(PdbTypeSymId type_id, - const llvm::codeview::ModifierRecord &mr); + const llvm::codeview::ModifierRecord &mr, + CompilerType ct); lldb::TypeSP CreatePointerType(PdbTypeSymId type_id, - const llvm::codeview::PointerRecord &pr); - lldb::TypeSP CreateSimpleType(llvm::codeview::TypeIndex ti); + const llvm::codeview::PointerRecord &pr, + CompilerType ct); + lldb::TypeSP CreateSimpleType(llvm::codeview::TypeIndex ti, CompilerType ct); lldb::TypeSP CreateTagType(PdbTypeSymId type_id, - const llvm::codeview::ClassRecord &cr); + const llvm::codeview::ClassRecord &cr, + CompilerType ct); lldb::TypeSP CreateTagType(PdbTypeSymId type_id, - const llvm::codeview::EnumRecord &er); + const llvm::codeview::EnumRecord &er, + CompilerType ct); lldb::TypeSP CreateTagType(PdbTypeSymId type_id, - const llvm::codeview::UnionRecord &ur); + const llvm::codeview::UnionRecord &ur, + CompilerType ct); lldb::TypeSP CreateArrayType(PdbTypeSymId type_id, - const llvm::codeview::ArrayRecord &ar); + const llvm::codeview::ArrayRecord &ar, + CompilerType ct); lldb::TypeSP CreateProcedureType(PdbTypeSymId type_id, - const llvm::codeview::ProcedureRecord &pr); - lldb::TypeSP - CreateClassStructUnion(PdbTypeSymId type_id, - const llvm::codeview::TagRecord &record, size_t size, - clang::TagTypeKind ttk, - clang::MSInheritanceAttr::Spelling inheritance); + const llvm::codeview::ProcedureRecord &pr, + CompilerType ct); + lldb::TypeSP CreateClassStructUnion(PdbTypeSymId type_id, + const llvm::codeview::TagRecord &record, + size_t size, CompilerType ct); lldb::FunctionSP GetOrCreateFunction(PdbCompilandSymId func_id, CompileUnit &comp_unit); @@ -210,7 +201,7 @@ private: lldb::VariableSP CreateLocalVariable(PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param); lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci); - lldb::TypeSP CreateType(PdbTypeSymId type_id); + lldb::TypeSP CreateType(PdbTypeSymId type_id, CompilerType ct); lldb::TypeSP CreateAndCacheType(PdbTypeSymId type_id); lldb::VariableSP CreateGlobalVariable(PdbGlobalSymId var_id); lldb::VariableSP CreateConstantSymbol(PdbGlobalSymId var_id, @@ -224,14 +215,8 @@ private: lldb::addr_t m_obj_load_address = 0; std::unique_ptr<PdbIndex> m_index; - std::unique_ptr<ClangASTImporter> m_importer; - ClangASTContext *m_clang = nullptr; - - llvm::DenseMap<clang::TagDecl *, DeclStatus> m_decl_to_status; - llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl; - llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex> - m_parent_types; + std::unique_ptr<PdbAstBuilder> m_ast; llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_global_vars; llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_local_variables; diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index 88eb6a8d917..239dfbee625 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -1,11 +1,12 @@ #include "UdtRecordCompleter.h" +#include "PdbAstBuilder.h" #include "PdbIndex.h" #include "PdbSymUid.h" #include "PdbUtil.h" -#include "SymbolFileNativePDB.h" #include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/Type.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" @@ -27,11 +28,11 @@ using Error = llvm::Error; UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl, - SymbolFileNativePDB &symbol_file) + PdbAstBuilder &ast_builder, + TpiStream &tpi) : m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl), - m_symbol_file(symbol_file) { - TpiStream &tpi = symbol_file.m_index->tpi(); - CVType cvt = tpi.getType(m_id.index); + m_ast_builder(ast_builder), m_tpi(tpi) { + CVType cvt = m_tpi.getType(m_id.index); switch (cvt.kind()) { case LF_ENUM: llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er)); @@ -48,29 +49,29 @@ UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id, } } -lldb::opaque_compiler_type_t UdtRecordCompleter::AddBaseClassForTypeIndex( +clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex( llvm::codeview::TypeIndex ti, llvm::codeview::MemberAccess access) { - TypeSP base_type = m_symbol_file.GetOrCreateType(ti); - CompilerType base_ct = base_type->GetFullCompilerType(); + PdbTypeSymId type_id(ti); + clang::QualType qt = m_ast_builder.GetOrCreateType(type_id); - CVType udt_cvt = m_symbol_file.m_index->tpi().getType(ti); + CVType udt_cvt = m_tpi.getType(ti); - lldb::opaque_compiler_type_t base_qt = base_ct.GetOpaqueQualType(); std::unique_ptr<clang::CXXBaseSpecifier> base_spec = - m_symbol_file.GetASTContext().CreateBaseClassSpecifier( - base_qt, TranslateMemberAccess(access), false, + m_ast_builder.clang().CreateBaseClassSpecifier( + qt.getAsOpaquePtr(), TranslateMemberAccess(access), false, udt_cvt.kind() == LF_CLASS); lldbassert(base_spec); m_bases.push_back(std::move(base_spec)); - return base_qt; + return qt; } Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, BaseClassRecord &base) { - lldb::opaque_compiler_type_t base_qt = + clang::QualType base_qt = AddBaseClassForTypeIndex(base.Type, base.getAccess()); - auto decl = m_symbol_file.GetASTContext().GetAsCXXRecordDecl(base_qt); + auto decl = + m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr()); lldbassert(decl); auto offset = clang::CharUnits::fromQuantity(base.getBaseOffset()); @@ -99,13 +100,17 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, 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(); + clang::QualType member_type = + m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type)); + + m_ast_builder.CompleteType(member_type); + + CompilerType member_ct = m_ast_builder.ToCompilerType(member_type); lldb::AccessType access = TranslateMemberAccess(static_data_member.getAccess()); ClangASTContext::AddVariableToRecordType( - m_derived_ct, static_data_member.Name, complete_member_type, access); + m_derived_ct, static_data_member.Name, member_ct, access); // FIXME: Add a PdbSymUid namespace for field list members and update // the m_uid_to_decl map with this decl. @@ -123,11 +128,9 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, uint64_t offset = data_member.FieldOffset * 8; uint32_t bitfield_width = 0; - TypeSP member_type; - TpiStream &tpi = m_symbol_file.m_index->tpi(); TypeIndex ti(data_member.Type); if (!ti.isSimple()) { - CVType cvt = tpi.getType(ti); + CVType cvt = m_tpi.getType(ti); if (cvt.kind() == LF_BITFIELD) { BitFieldRecord bfr; llvm::cantFail(TypeDeserializer::deserializeAs<BitFieldRecord>(cvt, bfr)); @@ -137,13 +140,14 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, } } - member_type = m_symbol_file.GetOrCreateType(ti); - CompilerType complete_member_type = member_type->GetFullCompilerType(); + clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti)); + m_ast_builder.CompleteType(member_qt); + lldb::AccessType access = TranslateMemberAccess(data_member.getAccess()); clang::FieldDecl *decl = ClangASTContext::AddFieldToRecordType( - m_derived_ct, data_member.Name, complete_member_type, access, - bitfield_width); + m_derived_ct, data_member.Name, m_ast_builder.ToCompilerType(member_qt), + access, bitfield_width); // FIXME: Add a PdbSymUid namespace for field list members and update // the m_uid_to_decl map with this decl. @@ -164,22 +168,16 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr, EnumeratorRecord &enumerator) { - ClangASTContext &clang = m_symbol_file.GetASTContext(); - Declaration decl; llvm::StringRef name = DropNameScope(enumerator.getName()); - TypeSP underlying_type = - m_symbol_file.GetOrCreateType(m_cvr.er.getUnderlyingType()); - uint64_t byte_size = underlying_type->GetByteSize(); - clang.AddEnumerationValueToEnumerationType( - m_derived_ct, decl, name.str().c_str(), enumerator.Value.getSExtValue(), - byte_size * 8); + m_ast_builder.clang().AddEnumerationValueToEnumerationType( + m_derived_ct, decl, name.str().c_str(), enumerator.Value); return Error::success(); } void UdtRecordCompleter::complete() { - ClangASTContext &clang = m_symbol_file.GetASTContext(); + ClangASTContext &clang = m_ast_builder.clang(); clang.TransferBaseClasses(m_derived_ct.GetOpaqueQualType(), std::move(m_bases)); @@ -188,6 +186,6 @@ void UdtRecordCompleter::complete() { ClangASTContext::CompleteTagDeclarationDefinition(m_derived_ct); if (auto *record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(&m_tag_decl)) { - m_symbol_file.GetASTImporter().InsertRecordDecl(record_decl, m_layout); + m_ast_builder.importer().InsertRecordDecl(record_decl, m_layout); } } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h index 1b2fca2ff7d..469685126e5 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h @@ -19,14 +19,21 @@ namespace clang { class CXXBaseSpecifier; +class QualType; class TagDecl; } // namespace clang +namespace llvm { +namespace pdb { +class TpiStream; +} +} // namespace llvm + namespace lldb_private { class Type; class CompilerType; namespace npdb { -class SymbolFileNativePDB; +class PdbAstBuilder; class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks { union UdtTagRecord { @@ -39,14 +46,15 @@ class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks { PdbTypeSymId m_id; CompilerType &m_derived_ct; clang::TagDecl &m_tag_decl; - SymbolFileNativePDB &m_symbol_file; + PdbAstBuilder &m_ast_builder; + llvm::pdb::TpiStream &m_tpi; std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> m_bases; ClangASTImporter::LayoutInfo m_layout; public: UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct, - clang::TagDecl &tag_decl, - SymbolFileNativePDB &symbol_file); + clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder, + llvm::pdb::TpiStream &tpi); #define MEMBER_RECORD(EnumName, EnumVal, Name) \ llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \ @@ -57,9 +65,8 @@ public: void complete(); private: - lldb::opaque_compiler_type_t - AddBaseClassForTypeIndex(llvm::codeview::TypeIndex ti, - llvm::codeview::MemberAccess access); + clang::QualType AddBaseClassForTypeIndex(llvm::codeview::TypeIndex ti, + llvm::codeview::MemberAccess access); }; } // namespace npdb |

