From a3e60044d75823a3cd8e35de76b7bde2599fe740 Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Fri, 23 Sep 2022 10:57:25 -0700 Subject: [PATCH] [LLDB][NativePDB] Let native pdb use class layout in debug info. Before, class layout in native pdb is not hooked up in [[https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp#L9375-L9380 | here]]. This changes hooked it up by refactoring SymbolFileNativePDB and PdbAstBuilder. PdbIndex (corresponds to a single pdb file) is removed from PdbAstBuilder, so it can only be accessed via SymbolFileNativePDB and we can construct PdbAstBuilder with just TypeSystemClang. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D134509 --- lldb/include/lldb/Symbol/TypeSystem.h | 6 +- .../Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp | 365 ++++++--------------- .../Plugins/SymbolFile/NativePDB/PdbAstBuilder.h | 7 +- .../SymbolFile/NativePDB/SymbolFileNativePDB.cpp | 334 +++++++++++++++++-- .../SymbolFile/NativePDB/SymbolFileNativePDB.h | 15 +- .../SymbolFile/NativePDB/UdtRecordCompleter.cpp | 2 +- .../Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 9 + .../Plugins/TypeSystem/Clang/TypeSystemClang.h | 2 + 8 files changed, 432 insertions(+), 308 deletions(-) diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 769449a..57bdfa5 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -31,6 +31,9 @@ class DWARFASTParser; class PDBASTParser; namespace lldb_private { +namespace npdb { + class PdbAstBuilder; +} // namespace npdb /// A SmallBitVector that represents a set of source languages (\p /// lldb::LanguageType). Each lldb::LanguageType is represented by @@ -88,6 +91,7 @@ public: virtual DWARFASTParser *GetDWARFParser() { return nullptr; } virtual PDBASTParser *GetPDBParser() { return nullptr; } + virtual npdb::PdbAstBuilder *GetNativePDBParser() { return nullptr; } virtual SymbolFile *GetSymbolFile() const { return m_sym_file; } @@ -366,7 +370,7 @@ public: LLVM_DUMP_METHOD virtual void dump(lldb::opaque_compiler_type_t type) const = 0; #endif - + virtual void DumpValue(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format, const DataExtractor &data, diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index ab467f2..2e17aa1 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -24,6 +24,7 @@ #include "PdbUtil.h" #include "UdtRecordCompleter.h" +#include "SymbolFileNativePDB.h" using namespace lldb_private; using namespace lldb_private::npdb; @@ -94,59 +95,6 @@ struct CreateMethodDecl : public TypeVisitorCallbacks { }; } // namespace -static llvm::Optional 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 scope_stack; - - while (begin != end) { - 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.offset) { - 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; - } - if (scope_stack.empty()) - return llvm::None; - // We have a match! Return the top of the stack - return scope_stack.back(); -} - static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) { switch (cr.Kind) { case TypeRecordKind::Class: @@ -207,65 +155,11 @@ TranslateCallingConvention(llvm::codeview::CallingConvention conv) { } } -static llvm::Optional -GetNestedTagDefinition(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 = std::string(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; - if (qname[3] == 'W') - piece = "4"; - piece += Record.Name; - piece.push_back('@'); - qname.insert(4, std::move(piece)); - if (qname != child.asTag().UniqueName) - return llvm::None; - - return std::move(child); -} - static bool IsAnonymousNamespaceName(llvm::StringRef name) { return name == "`anonymous namespace'" || name == "`anonymous-namespace'"; } -PdbAstBuilder::PdbAstBuilder(ObjectFile &obj, PdbIndex &index, TypeSystemClang &clang) - : m_index(index), m_clang(clang) { - BuildParentMap(); -} +PdbAstBuilder::PdbAstBuilder(TypeSystemClang &clang) : m_clang(clang) {} lldb_private::CompilerDeclContext PdbAstBuilder::GetTranslationUnitDecl() { return ToCompilerDeclContext(*m_clang.GetTranslationUnitDecl()); @@ -273,6 +167,8 @@ lldb_private::CompilerDeclContext PdbAstBuilder::GetTranslationUnitDecl() { std::pair PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); // FIXME: Move this to GetDeclContextContainingUID. if (!record.hasUniqueName()) return CreateDeclInfoForUndecoratedName(record.Name); @@ -297,8 +193,8 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { // 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()) { + llvm::Optional parent_index = pdb->GetParentType(ti); + if (!parent_index) { if (scopes.empty()) return {context, uname}; @@ -322,7 +218,7 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { // 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); + clang::QualType parent_qt = GetOrCreateType(*parent_index); if (parent_qt.isNull()) return {nullptr, ""}; @@ -330,120 +226,6 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { return {context, uname}; } -void PdbAstBuilder::BuildParentMap() { - LazyRandomTypeCollection &types = m_index.tpi().typeCollection(); - - llvm::DenseMap forward_to_full; - llvm::DenseMap full_to_forward; - - struct RecordIndices { - TypeIndex forward; - TypeIndex full; - }; - - llvm::StringMap record_indices; - - for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) { - CVType type = types.getType(*ti); - if (!IsTagRecord(type)) - continue; - - CVTagRecord tag = CVTagRecord::create(type); - - RecordIndices &indices = record_indices[tag.asTag().getUniqueName()]; - if (tag.asTag().isForwardRef()) - indices.forward = *ti; - else - indices.full = *ti; - - if (indices.full != TypeIndex::None() && - indices.forward != TypeIndex::None()) { - forward_to_full[indices.forward] = indices.full; - full_to_forward[indices.full] = indices.forward; - } - - // 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 &parents) - : index(index), parents(parents), parent(parent), - parent_cvt(parent_cvt) {} - - PdbIndex &index; - llvm::DenseMap &parents; - - unsigned unnamed_type_index = 1; - TypeIndex parent; - const CVTagRecord &parent_cvt; - - llvm::Error visitKnownMember(CVMemberRecord &CVR, - NestedTypeRecord &Record) override { - std::string unnamed_type_name; - if (Record.Name.empty()) { - unnamed_type_name = - llvm::formatv("", unnamed_type_index).str(); - Record.Name = unnamed_type_name; - ++unnamed_type_index; - } - llvm::Optional tag = - GetNestedTagDefinition(Record, parent_cvt, index.tpi()); - if (!tag) - return llvm::ErrorSuccess(); - - parents[Record.Type] = parent; - return llvm::ErrorSuccess(); - } - }; - - CVType field_list_cvt = m_index.tpi().getType(tag.asTag().FieldList); - ProcessTpiStream process(m_index, *ti, tag, m_parent_types); - FieldListRecord field_list; - if (llvm::Error error = TypeDeserializer::deserializeAs( - field_list_cvt, field_list)) - llvm::consumeError(std::move(error)); - if (llvm::Error error = visitMemberRecordStream(field_list.Data, process)) - llvm::consumeError(std::move(error)); - } - - // Now that we know the forward -> full mapping of all type indices, we can - // re-write all the indices. At the end of this process, we want a mapping - // consisting of fwd -> full and full -> full for all child -> parent indices. - // We can re-write the values in place, but for the keys, we must save them - // off so that we don't modify the map in place while also iterating it. - std::vector full_keys; - std::vector fwd_keys; - for (auto &entry : m_parent_types) { - TypeIndex key = entry.first; - TypeIndex value = entry.second; - - auto iter = forward_to_full.find(value); - if (iter != forward_to_full.end()) - entry.second = iter->second; - - iter = forward_to_full.find(key); - if (iter != forward_to_full.end()) - fwd_keys.push_back(key); - else - full_keys.push_back(key); - } - for (TypeIndex fwd : fwd_keys) { - TypeIndex full = forward_to_full[fwd]; - m_parent_types[full] = m_parent_types[fwd]; - } - for (TypeIndex full : full_keys) { - TypeIndex fwd = full_to_forward[full]; - m_parent_types[fwd] = m_parent_types[full]; - } - - // Now that -} - static bool isLocalVariableType(SymbolKind K) { switch (K) { case S_REGISTER: @@ -457,7 +239,10 @@ static bool isLocalVariableType(SymbolKind K) { } clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) { - CVSymbol cvs = m_index.ReadSymbolRecord(id); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVSymbol cvs = index.ReadSymbolRecord(id); if (isLocalVariableType(cvs.kind())) { clang::DeclContext *scope = GetParentDeclContext(id); @@ -534,6 +319,9 @@ clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) { std::pair PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); MSVCUndecoratedNameParser parser(name); llvm::ArrayRef specs = parser.GetSpecifiers(); @@ -547,7 +335,7 @@ PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { llvm::StringRef scope_name = specs.back().GetFullName(); // It might be a class name, try that first. - std::vector types = m_index.tpi().findRecordsByName(scope_name); + std::vector types = index.tpi().findRecordsByName(scope_name); while (!types.empty()) { clang::QualType qt = GetOrCreateType(types.back()); if (qt.isNull()) @@ -569,24 +357,27 @@ PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) { // We must do this *without* calling GetOrCreate on the current uid, as // that would be an infinite recursion. + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex& index = pdb->GetIndex(); switch (uid.kind()) { case PdbSymUidKind::CompilandSym: { llvm::Optional scope = - FindSymbolScope(m_index, uid.asCompilandSym()); + pdb->FindSymbolScope(uid.asCompilandSym()); if (scope) return GetOrCreateDeclContextForUid(*scope); - CVSymbol sym = m_index.ReadSymbolRecord(uid.asCompilandSym()); + CVSymbol sym = index.ReadSymbolRecord(uid.asCompilandSym()); return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; } 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. PdbTypeSymId type_id = uid.asTypeSym(); - auto iter = m_parent_types.find(type_id.index); - if (iter == m_parent_types.end()) + llvm::Optional parent_index = pdb->GetParentType(type_id.index); + if (!parent_index) return FromCompilerDeclContext(GetTranslationUnitDecl()); - return GetOrCreateDeclContextForUid(PdbTypeSymId(iter->second)); + return GetOrCreateDeclContextForUid(PdbTypeSymId(*parent_index)); } case PdbSymUidKind::FieldListMember: // In this case the parent DeclContext is the one for the class that this @@ -599,7 +390,7 @@ clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) { // that up in the TPI stream. If it's found, it's a type, othewrise it's // a series of namespaces. // FIXME: do this. - CVSymbol global = m_index.ReadSymbolRecord(uid.asGlobalSym()); + CVSymbol global = index.ReadSymbolRecord(uid.asGlobalSym()); switch (global.kind()) { case SymbolKind::S_GDATA32: case SymbolKind::S_LDATA32: @@ -651,19 +442,21 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { return true; PdbTypeSymId type_id = PdbSymUid(status.uid).asTypeSym(); - - lldbassert(IsTagRecord(type_id, m_index.tpi())); + PdbIndex &index = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()) + ->GetIndex(); + lldbassert(IsTagRecord(type_id, index.tpi())); clang::QualType tag_qt = m_clang.getASTContext().getTypeDeclType(&tag); TypeSystemClang::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false); TypeIndex tag_ti = type_id.index; - CVType cvt = m_index.tpi().getType(tag_ti); + CVType cvt = 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); + PdbTypeSymId best_ti = GetBestPossibleDecl(tag_ti, index.tpi()); + cvt = index.tpi().getType(best_ti.index); lldbassert(IsTagRecord(cvt)); if (IsForwardRefUdt(cvt)) { @@ -673,7 +466,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { } TypeIndex field_list_ti = GetFieldListIndex(cvt); - CVType field_list_cvt = m_index.tpi().getType(field_list_ti); + CVType field_list_cvt = index.tpi().getType(field_list_ti); if (field_list_cvt.kind() != LF_FIELDLIST) return false; FieldListRecord field_list; @@ -684,7 +477,7 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { // 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, + UdtRecordCompleter completer(best_ti, ct, tag, *this, index, m_cxx_record_map); llvm::Error error = llvm::codeview::visitMemberRecordStream(field_list.Data, completer); @@ -900,7 +693,10 @@ PdbAstBuilder::GetOrCreateVariableDecl(PdbCompilandSymId scope_id, if (!scope) return nullptr; - CVSymbol sym = m_index.ReadSymbolRecord(var_id); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVSymbol sym = index.ReadSymbolRecord(var_id); return CreateVariableDecl(PdbSymUid(var_id), sym, *scope); } @@ -908,7 +704,10 @@ clang::VarDecl *PdbAstBuilder::GetOrCreateVariableDecl(PdbGlobalSymId var_id) { if (clang::Decl *decl = TryGetDecl(var_id)) return llvm::dyn_cast(decl); - CVSymbol sym = m_index.ReadSymbolRecord(var_id); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVSymbol sym = index.ReadSymbolRecord(var_id); auto context = FromCompilerDeclContext(GetTranslationUnitDecl()); return CreateVariableDecl(PdbSymUid(var_id), sym, *context); } @@ -918,7 +717,10 @@ PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { if (clang::Decl *decl = TryGetDecl(id)) return llvm::dyn_cast(decl); - CVSymbol sym = m_index.ReadSymbolRecord(id); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVSymbol sym = index.ReadSymbolRecord(id); lldbassert(sym.kind() == S_UDT); UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs(sym)); @@ -950,7 +752,10 @@ clang::QualType PdbAstBuilder::CreateType(PdbTypeSymId type) { if (type.index.isSimple()) return CreateSimpleType(type.index); - CVType cvt = m_index.tpi().getType(type.index); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVType cvt = index.tpi().getType(type.index); if (cvt.kind() == LF_MODIFIER) { ModifierRecord modifier; @@ -1006,7 +811,10 @@ clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) { if (iter != m_uid_to_type.end()) return iter->second; - PdbTypeSymId best_type = GetBestPossibleDecl(type, m_index.tpi()); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + PdbTypeSymId best_type = GetBestPossibleDecl(type, index.tpi()); clang::QualType qt; if (best_type.index != type.index) { @@ -1026,7 +834,7 @@ clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) { return {}; m_uid_to_type[toOpaqueUid(type)] = qt; - if (IsTagRecord(type, m_index.tpi())) { + if (IsTagRecord(type, index.tpi())) { clang::TagDecl *tag = qt->getAsTagDecl(); lldbassert(m_decl_to_status.count(tag) == 0); @@ -1045,6 +853,9 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id, bool is_inline, clang::DeclContext *parent) { clang::FunctionDecl *function_decl = nullptr; if (parent->isRecord()) { + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); clang::QualType parent_qt = llvm::cast(parent) ->getTypeForDecl() ->getCanonicalTypeInternal(); @@ -1058,29 +869,29 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id, } } - CVType cvt = m_index.tpi().getType(func_ti); + CVType cvt = index.tpi().getType(func_ti); MemberFunctionRecord func_record(static_cast(cvt.kind())); llvm::cantFail(TypeDeserializer::deserializeAs( cvt, func_record)); TypeIndex class_index = func_record.getClassType(); - CVType parent_cvt = m_index.tpi().getType(class_index); + CVType parent_cvt = index.tpi().getType(class_index); TagRecord tag_record = CVTagRecord::create(parent_cvt).asTag(); // If it's a forward reference, try to get the real TypeIndex. if (tag_record.isForwardRef()) { llvm::Expected eti = - m_index.tpi().findFullDeclForForwardRef(class_index); + index.tpi().findFullDeclForForwardRef(class_index); if (eti) { - tag_record = CVTagRecord::create(m_index.tpi().getType(*eti)).asTag(); + tag_record = CVTagRecord::create(index.tpi().getType(*eti)).asTag(); } } if (!tag_record.FieldList.isSimple()) { - CVType field_list_cvt = m_index.tpi().getType(tag_record.FieldList); + CVType field_list_cvt = index.tpi().getType(tag_record.FieldList); FieldListRecord field_list; if (llvm::Error error = TypeDeserializer::deserializeAs( field_list_cvt, field_list)) llvm::consumeError(std::move(error)); - CreateMethodDecl process(m_index, m_clang, func_ti, function_decl, + CreateMethodDecl process(index, m_clang, func_ti, function_decl, parent_opaque_ty, func_name, func_ct); if (llvm::Error err = visitMemberRecordStream(field_list.Data, process)) llvm::consumeError(std::move(err)); @@ -1107,8 +918,11 @@ PdbAstBuilder::CreateFunctionDecl(PdbCompilandSymId func_id, clang::FunctionDecl * PdbAstBuilder::GetOrCreateInlinedFunctionDecl(PdbCompilandSymId inlinesite_id) { + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); CompilandIndexItem *cii = - m_index.compilands().GetCompiland(inlinesite_id.modi); + index.compilands().GetCompiland(inlinesite_id.modi); CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(inlinesite_id.offset); InlineSiteSym inline_site(static_cast(sym.kind())); cantFail(SymbolDeserializer::deserializeAs(sym, inline_site)); @@ -1145,7 +959,10 @@ clang::FunctionDecl * PdbAstBuilder::CreateFunctionDeclFromId(PdbTypeSymId func_tid, PdbCompilandSymId func_sid) { lldbassert(func_tid.is_ipi); - CVType func_cvt = m_index.ipi().getType(func_tid.index); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVType func_cvt = index.ipi().getType(func_tid.index); llvm::StringRef func_name; TypeIndex func_ti; clang::DeclContext *parent = nullptr; @@ -1167,7 +984,7 @@ PdbAstBuilder::CreateFunctionDeclFromId(PdbTypeSymId func_tid, func_ti = fir.getFunctionType(); parent = FromCompilerDeclContext(GetTranslationUnitDecl()); if (!fir.ParentScope.isNoneType()) { - CVType parent_cvt = m_index.ipi().getType(fir.ParentScope); + CVType parent_cvt = index.ipi().getType(fir.ParentScope); if (parent_cvt.kind() == LF_STRING_ID) { StringIdRecord sir; cantFail( @@ -1205,7 +1022,10 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { context_name = tag->getQualifiedNameAsString(); } - CVSymbol cvs = m_index.ReadSymbolRecord(func_id); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVSymbol cvs = index.ReadSymbolRecord(func_id); ProcSym proc(static_cast(cvs.kind())); llvm::cantFail(SymbolDeserializer::deserializeAs(cvs, proc)); @@ -1245,7 +1065,10 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, clang::FunctionDecl &function_decl, uint32_t param_count) { - CompilandIndexItem *cii = m_index.compilands().GetCompiland(func_id.modi); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CompilandIndexItem *cii = index.compilands().GetCompiland(func_id.modi); CVSymbolArray scope = cii->m_debug_stream.getSymbolArrayForScope(func_id.offset); @@ -1340,7 +1163,10 @@ clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) { clang::QualType element_type = GetOrCreateType(ar.ElementType); - uint64_t element_size = GetSizeOfType({ar.ElementType}, m_index.tpi()); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + uint64_t element_size = GetSizeOfType({ar.ElementType}, index.tpi()); if (element_type.isNull() || element_size == 0) return {}; uint64_t element_count = ar.Size / element_size; @@ -1353,7 +1179,10 @@ clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) { clang::QualType PdbAstBuilder::CreateFunctionType( TypeIndex args_type_idx, TypeIndex return_type_idx, llvm::codeview::CallingConvention calling_convention) { - TpiStream &stream = m_index.tpi(); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + TpiStream &stream = index.tpi(); CVType args_cvt = stream.getType(args_type_idx); ArgListRecord args; llvm::cantFail( @@ -1405,8 +1234,11 @@ static bool isBlockDecl(clang::DeclContext &context) { void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf( llvm::Optional parent) { - TypeIndex ti{m_index.tpi().TypeIndexBegin()}; - for (const CVType &cvt : m_index.tpi().typeArray()) { + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + TypeIndex ti{index.tpi().TypeIndexBegin()}; + for (const CVType &cvt : index.tpi().typeArray()) { PdbTypeSymId tid{ti}; ++ti; @@ -1439,9 +1271,9 @@ void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf( } } - uint32_t module_count = m_index.dbi().modules().getModuleCount(); + uint32_t module_count = index.dbi().modules().getModuleCount(); for (uint16_t modi = 0; modi < module_count; ++modi) { - CompilandIndexItem &cii = m_index.compilands().GetOrCreateCompiland(modi); + CompilandIndexItem &cii = index.compilands().GetOrCreateCompiland(modi); const CVSymbolArray &symbols = cii.m_debug_stream.getSymbolArray(); auto iter = symbols.begin(); while (iter != symbols.end()) { @@ -1495,11 +1327,14 @@ static CVSymbolArray skipFunctionParameters(clang::Decl &decl, } void PdbAstBuilder::ParseBlockChildren(PdbCompilandSymId block_id) { - CVSymbol sym = m_index.ReadSymbolRecord(block_id); + SymbolFileNativePDB *pdb = static_cast( + m_clang.GetSymbolFile()->GetBackingSymbolFile()); + PdbIndex &index = pdb->GetIndex(); + CVSymbol sym = index.ReadSymbolRecord(block_id); lldbassert(sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32 || sym.kind() == S_BLOCK32 || sym.kind() == S_INLINESITE); CompilandIndexItem &cii = - m_index.compilands().GetOrCreateCompiland(block_id.modi); + index.compilands().GetOrCreateCompiland(block_id.modi); CVSymbolArray symbols = cii.m_debug_stream.getSymbolArrayForScope(block_id.offset); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h index e4d9c6e..b94176e 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h @@ -51,7 +51,7 @@ struct DeclStatus { class PdbAstBuilder { public: // Constructors and Destructors - PdbAstBuilder(ObjectFile &obj, PdbIndex &index, TypeSystemClang &clang); + PdbAstBuilder(TypeSystemClang &clang); lldb_private::CompilerDeclContext GetTranslationUnitDecl(); @@ -83,7 +83,7 @@ public: clang::DeclContext *FromCompilerDeclContext(CompilerDeclContext context); TypeSystemClang &clang() { return m_clang; } - ClangASTImporter &importer() { return m_importer; } + ClangASTImporter &GetClangASTImporter() { return m_importer; } void Dump(Stream &stream); @@ -126,19 +126,16 @@ private: void ParseDeclsForSimpleContext(clang::DeclContext &context); void ParseBlockChildren(PdbCompilandSymId block_id); - void BuildParentMap(); std::pair CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti); std::pair CreateDeclInfoForUndecoratedName(llvm::StringRef uname); clang::QualType CreateSimpleType(TypeIndex ti); - PdbIndex &m_index; TypeSystemClang &m_clang; ClangASTImporter m_importer; - llvm::DenseMap m_parent_types; llvm::DenseMap m_decl_to_status; llvm::DenseMap m_uid_to_decl; llvm::DenseMap m_uid_to_type; diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 304b649..a34ce04 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -8,12 +8,6 @@ #include "SymbolFileNativePDB.h" -#include "clang/AST/Attr.h" -#include "clang/AST/CharUnits.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/Type.h" - #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" #include "Plugins/ObjectFile/PDB/ObjectFilePDB.h" @@ -59,7 +53,6 @@ #include "llvm/Support/MemoryBuffer.h" #include "DWARFLocationExpression.h" -#include "PdbAstBuilder.h" #include "PdbSymUid.h" #include "PdbUtil.h" #include "UdtRecordCompleter.h" @@ -233,6 +226,57 @@ static bool IsClassRecord(TypeLeafKind kind) { } } +static llvm::Optional +GetNestedTagDefinition(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 = std::string(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; + if (qname[3] == 'W') + piece = "4"; + 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::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, @@ -311,9 +355,7 @@ void SymbolFileNativePDB::InitializeObject() { "Failed to initialize"); } else { ts_or_err->SetSymbolFile(this); - auto *clang = llvm::cast_or_null(&ts_or_err.get()); - lldbassert(clang); - m_ast = std::make_unique(*m_objfile_sp, *m_index, *clang); + BuildParentMap(); } } @@ -338,6 +380,10 @@ Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) { CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii); lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id); BlockSP child_block = std::make_shared(opaque_block_uid); + auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage()); + if (auto err = ts_or_err.takeError()) + return *child_block; + PdbAstBuilder* ast_builder = ts_or_err->GetNativePDBParser(); switch (sym.kind()) { case S_GPROC32: @@ -381,7 +427,7 @@ Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) { block_base + block.CodeSize, func_base); } parent_block.AddChild(child_block); - m_ast->GetOrCreateBlockDecl(block_id); + ast_builder->GetOrCreateBlockDecl(block_id); m_blocks.insert({opaque_block_uid, child_block}); break; } @@ -392,7 +438,7 @@ Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) { std::shared_ptr inline_site = m_inline_sites[opaque_block_uid]; Block &parent_block = GetOrCreateBlock(inline_site->parent_id); parent_block.AddChild(child_block); - m_ast->GetOrCreateInlinedFunctionDecl(block_id); + ast_builder->GetOrCreateInlinedFunctionDecl(block_id); // Copy ranges from InlineSite to Block. for (size_t i = 0; i < inline_site->ranges.GetSize(); ++i) { auto *entry = inline_site->ranges.GetEntryAtIndex(i); @@ -453,7 +499,10 @@ lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id, comp_unit.AddFunction(func_sp); - m_ast->GetOrCreateFunctionDecl(func_id); + auto ts_or_err = GetTypeSystemForLanguage(comp_unit.GetLanguage()); + if (auto err = ts_or_err.takeError()) + return func_sp; + ts_or_err->GetNativePDBParser()->GetOrCreateFunctionDecl(func_id); return func_sp; } @@ -746,12 +795,15 @@ TypeSP SymbolFileNativePDB::CreateAndCacheType(PdbTypeSymId type_id) { } PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id; - - clang::QualType qt = m_ast->GetOrCreateType(best_decl_id); + auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + if (auto err = ts_or_err.takeError()) + return nullptr; + PdbAstBuilder* ast_builder = ts_or_err->GetNativePDBParser(); + clang::QualType qt = ast_builder->GetOrCreateType(best_decl_id); if (qt.isNull()) return nullptr; - TypeSP result = CreateType(best_decl_id, m_ast->ToCompilerType(qt)); + TypeSP result = CreateType(best_decl_id, ast_builder->ToCompilerType(qt)); if (!result) return nullptr; @@ -840,8 +892,10 @@ VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) { SymbolFileTypeSP type_sp = std::make_shared(*this, toOpaqueUid(tid)); Variable::RangeList ranges; - - m_ast->GetOrCreateVariableDecl(var_id); + auto ts_or_err = GetTypeSystemForLanguage(comp_unit->GetLanguage()); + if (auto err = ts_or_err.takeError()) + return nullptr; + ts_or_err->GetNativePDBParser()->GetOrCreateVariableDecl(var_id); ModuleSP module_sp = GetObjectFile()->GetModule(); DWARFExpressionList location( @@ -941,10 +995,14 @@ Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) { void SymbolFileNativePDB::ParseDeclsForContext( lldb_private::CompilerDeclContext decl_ctx) { - clang::DeclContext *context = m_ast->FromCompilerDeclContext(decl_ctx); + TypeSystem* ts_or_err = decl_ctx.GetTypeSystem(); + if (!ts_or_err) + return; + PdbAstBuilder* ast_builder = ts_or_err->GetNativePDBParser(); + clang::DeclContext *context = ast_builder->FromCompilerDeclContext(decl_ctx); if (!context) return; - m_ast->ParseDeclsForContext(*context); + ast_builder->ParseDeclsForContext(*context); } lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) { @@ -1563,7 +1621,16 @@ size_t SymbolFileNativePDB::ParseSymbolArrayInScope( return count; } -void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); } +void SymbolFileNativePDB::DumpClangAST(Stream &s) { + auto ts_or_err = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus); + if (!ts_or_err) + return; + TypeSystemClang *clang = + llvm::dyn_cast_or_null(&ts_or_err.get()); + if (!clang) + return; + clang->GetNativePDBParser()->Dump(s); +} void SymbolFileNativePDB::FindGlobalVariables( ConstString name, const CompilerDeclContext &parent_decl_ctx, @@ -1767,8 +1834,12 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, &block, scope_ranges, &decl, var_info.location, external, artificial, location_is_constant_data, static_member); - if (!is_param) - m_ast->GetOrCreateVariableDecl(scope_id, var_id); + if (!is_param) { + auto ts_or_err = GetTypeSystemForLanguage(comp_unit_sp->GetLanguage()); + if (auto err = ts_or_err.takeError()) + return nullptr; + ts_or_err->GetNativePDBParser()->GetOrCreateVariableDecl(scope_id, var_id); + } m_local_variables[toOpaqueUid(var_id)] = var_sp; return var_sp; } @@ -1790,7 +1861,10 @@ TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) { TypeSP target_type = GetOrCreateType(udt.Type); - (void)m_ast->GetOrCreateTypedefDecl(id); + auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + if (auto err = ts_or_err.takeError()) + return nullptr; + ts_or_err->GetNativePDBParser()->GetOrCreateTypedefDecl(id); Declaration decl; return std::make_shared( @@ -1924,28 +1998,38 @@ size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) { } CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) { - if (auto decl = m_ast->GetOrCreateDeclForUid(uid)) - return *decl; - else + auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + if (auto err = ts_or_err.takeError()) return CompilerDecl(); + if (auto decl = ts_or_err->GetNativePDBParser()->GetOrCreateDeclForUid(uid)) + return *decl; + return CompilerDecl(); } CompilerDeclContext SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) { + auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + if (auto err = ts_or_err.takeError()) + return {}; + PdbAstBuilder *ast_builder = ts_or_err->GetNativePDBParser(); clang::DeclContext *context = - m_ast->GetOrCreateDeclContextForUid(PdbSymUid(uid)); + ast_builder->GetOrCreateDeclContextForUid(PdbSymUid(uid)); if (!context) return {}; - return m_ast->ToCompilerDeclContext(*context); + return ast_builder->ToCompilerDeclContext(*context); } CompilerDeclContext SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { - clang::DeclContext *context = m_ast->GetParentDeclContext(PdbSymUid(uid)); + auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); + if (auto err = ts_or_err.takeError()) + return CompilerDeclContext(); + PdbAstBuilder *ast_builder = ts_or_err->GetNativePDBParser(); + clang::DeclContext *context = ast_builder->GetParentDeclContext(PdbSymUid(uid)); if (!context) return CompilerDeclContext(); - return m_ast->ToCompilerDeclContext(*context); + return ast_builder->ToCompilerDeclContext(*context); } Type *SymbolFileNativePDB::ResolveTypeUID(lldb::user_id_t type_uid) { @@ -1977,12 +2061,23 @@ SymbolFileNativePDB::GetDynamicArrayInfoForUID( return llvm::None; } - bool SymbolFileNativePDB::CompleteType(CompilerType &compiler_type) { + std::lock_guard guard(GetModuleMutex()); + + TypeSystemClang *clang_type_system = + llvm::dyn_cast_or_null(compiler_type.GetTypeSystem()); + if (!clang_type_system) + return false; + + PdbAstBuilder *ast_builder = + static_cast(clang_type_system->GetNativePDBParser()); + if (ast_builder && + ast_builder->GetClangASTImporter().CanImport(compiler_type)) + return ast_builder->GetClangASTImporter().CompleteType(compiler_type); clang::QualType qt = clang::QualType::getFromOpaquePtr(compiler_type.GetOpaqueQualType()); - return m_ast->CompleteType(qt); + return ast_builder->CompleteType(qt); } void SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, @@ -2009,3 +2104,176 @@ uint64_t SymbolFileNativePDB::GetDebugInfoSize() { // PDB files are a separate file that contains all debug info. return m_index->pdb().getFileSize(); } + +void SymbolFileNativePDB::BuildParentMap() { + LazyRandomTypeCollection &types = m_index->tpi().typeCollection(); + + llvm::DenseMap forward_to_full; + llvm::DenseMap full_to_forward; + + struct RecordIndices { + TypeIndex forward; + TypeIndex full; + }; + + llvm::StringMap record_indices; + + for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) { + CVType type = types.getType(*ti); + if (!IsTagRecord(type)) + continue; + + CVTagRecord tag = CVTagRecord::create(type); + + RecordIndices &indices = record_indices[tag.asTag().getUniqueName()]; + if (tag.asTag().isForwardRef()) + indices.forward = *ti; + else + indices.full = *ti; + + if (indices.full != TypeIndex::None() && + indices.forward != TypeIndex::None()) { + forward_to_full[indices.forward] = indices.full; + full_to_forward[indices.full] = indices.forward; + } + + // 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 &parents) + : index(index), parents(parents), parent(parent), + parent_cvt(parent_cvt) {} + + PdbIndex &index; + llvm::DenseMap &parents; + + unsigned unnamed_type_index = 1; + TypeIndex parent; + const CVTagRecord &parent_cvt; + + llvm::Error visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Record) override { + std::string unnamed_type_name; + if (Record.Name.empty()) { + unnamed_type_name = + llvm::formatv("", unnamed_type_index).str(); + Record.Name = unnamed_type_name; + ++unnamed_type_index; + } + llvm::Optional tag = + GetNestedTagDefinition(Record, parent_cvt, index.tpi()); + if (!tag) + return llvm::ErrorSuccess(); + + parents[Record.Type] = parent; + return llvm::ErrorSuccess(); + } + }; + + CVType field_list_cvt = m_index->tpi().getType(tag.asTag().FieldList); + ProcessTpiStream process(*m_index, *ti, tag, m_parent_types); + FieldListRecord field_list; + if (llvm::Error error = TypeDeserializer::deserializeAs( + field_list_cvt, field_list)) + llvm::consumeError(std::move(error)); + if (llvm::Error error = visitMemberRecordStream(field_list.Data, process)) + llvm::consumeError(std::move(error)); + } + + // Now that we know the forward -> full mapping of all type indices, we can + // re-write all the indices. At the end of this process, we want a mapping + // consisting of fwd -> full and full -> full for all child -> parent indices. + // We can re-write the values in place, but for the keys, we must save them + // off so that we don't modify the map in place while also iterating it. + std::vector full_keys; + std::vector fwd_keys; + for (auto &entry : m_parent_types) { + TypeIndex key = entry.first; + TypeIndex value = entry.second; + + auto iter = forward_to_full.find(value); + if (iter != forward_to_full.end()) + entry.second = iter->second; + + iter = forward_to_full.find(key); + if (iter != forward_to_full.end()) + fwd_keys.push_back(key); + else + full_keys.push_back(key); + } + for (TypeIndex fwd : fwd_keys) { + TypeIndex full = forward_to_full[fwd]; + m_parent_types[full] = m_parent_types[fwd]; + } + for (TypeIndex full : full_keys) { + TypeIndex fwd = full_to_forward[full]; + m_parent_types[fwd] = m_parent_types[full]; + } +} + +llvm::Optional +SymbolFileNativePDB::FindSymbolScope(PdbCompilandSymId id) { + CVSymbol sym = m_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 = m_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 scope_stack; + + while (begin != end) { + 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.offset) { + 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; + } + if (scope_stack.empty()) + return llvm::None; + // We have a match! Return the top of the stack + return scope_stack.back(); +} + +llvm::Optional +SymbolFileNativePDB::GetParentType(llvm::codeview::TypeIndex ti) { + auto parent_iter = m_parent_types.find(ti); + if (parent_iter == m_parent_types.end()) + return llvm::None; + return parent_iter->second; +} diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index 4bb37d9..51ed121 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -19,6 +19,7 @@ #include "CompileUnitIndex.h" #include "PdbIndex.h" +#include "PdbAstBuilder.h" namespace clang { class TagDecl; @@ -37,7 +38,6 @@ struct UnionRecord; namespace lldb_private { namespace npdb { -class PdbAstBuilder; class SymbolFileNativePDB : public SymbolFileCommon { friend class UdtRecordCompleter; @@ -137,6 +137,8 @@ public: void FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) override; + llvm::Optional FindSymbolScope(PdbCompilandSymId id); + void FindTypes(ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet &searched_symbol_files, @@ -158,8 +160,13 @@ public: llvm::pdb::PDBFile &GetPDBFile() { return m_index->pdb(); } const llvm::pdb::PDBFile &GetPDBFile() const { return m_index->pdb(); } + PdbIndex &GetIndex() { return *m_index; }; + void DumpClangAST(Stream &s) override; + llvm::Optional + GetParentType(llvm::codeview::TypeIndex ti); + private: struct LineTableEntryComparator { bool operator()(const lldb_private::LineTable::Entry &lhs, @@ -180,6 +187,8 @@ private: InlineSite(PdbCompilandSymId parent_id) : parent_id(parent_id){}; }; + void BuildParentMap(); + uint32_t CalculateNumCompileUnits() override; lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; @@ -262,8 +271,6 @@ private: std::unique_ptr m_file_up; std::unique_ptr m_index; - std::unique_ptr m_ast; - llvm::DenseMap m_global_vars; llvm::DenseMap m_local_variables; llvm::DenseMap m_blocks; @@ -271,6 +278,8 @@ private: llvm::DenseMap m_compilands; llvm::DenseMap m_types; llvm::DenseMap> m_inline_sites; + llvm::DenseMap + m_parent_types; }; } // namespace npdb diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index c030819..16e9990 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -312,6 +312,6 @@ void UdtRecordCompleter::complete() { TypeSystemClang::CompleteTagDeclarationDefinition(m_derived_ct); if (auto *record_decl = llvm::dyn_cast(&m_tag_decl)) { - m_ast_builder.importer().SetRecordLayout(record_decl, m_layout); + m_ast_builder.GetClangASTImporter().SetRecordLayout(record_decl, m_layout); } } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 7e0a19c..4adf653 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -73,6 +73,7 @@ #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" #include "Plugins/SymbolFile/PDB/PDBASTParser.h" +#include "Plugins/SymbolFile/NativePDB/PdbAstBuilder.h" #include @@ -9364,6 +9365,12 @@ PDBASTParser *TypeSystemClang::GetPDBParser() { return m_pdb_ast_parser_up.get(); } +npdb::PdbAstBuilder *TypeSystemClang::GetNativePDBParser() { + if (!m_native_pdb_ast_parser_up) + m_native_pdb_ast_parser_up = std::make_unique(*this); + return m_native_pdb_ast_parser_up.get(); +} + bool TypeSystemClang::LayoutRecordType( const clang::RecordDecl *record_decl, uint64_t &bit_size, uint64_t &alignment, @@ -9377,6 +9384,8 @@ bool TypeSystemClang::LayoutRecordType( importer = &m_dwarf_ast_parser_up->GetClangASTImporter(); if (!importer && m_pdb_ast_parser_up) importer = &m_pdb_ast_parser_up->GetClangASTImporter(); + if (!importer && m_native_pdb_ast_parser_up) + importer = &m_native_pdb_ast_parser_up->GetClangASTImporter(); if (!importer) return false; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index ff8e12e..7c045fd 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -443,6 +443,7 @@ public: // TypeSystem methods DWARFASTParser *GetDWARFParser() override; PDBASTParser *GetPDBParser() override; + npdb::PdbAstBuilder *GetNativePDBParser() override; // TypeSystemClang callbacks for external source lookups. void CompleteTagDecl(clang::TagDecl *); @@ -1071,6 +1072,7 @@ private: std::unique_ptr m_module_map_up; std::unique_ptr m_dwarf_ast_parser_up; std::unique_ptr m_pdb_ast_parser_up; + std::unique_ptr m_native_pdb_ast_parser_up; std::unique_ptr m_mangle_ctx_up; uint32_t m_pointer_byte_size = 0; bool m_ast_owned = false; -- 2.7.4