diff options
Diffstat (limited to 'lldb/source')
4 files changed, 221 insertions, 18 deletions
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp index 385892f484c..e1ba03f276a 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -21,6 +21,38 @@ using namespace lldb_private::npdb; using namespace llvm::codeview; using namespace llvm::pdb; +CVTagRecord CVTagRecord::create(CVType type) { + assert(IsTagRecord(type) && "type is not a tag record!"); + switch (type.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: { + ClassRecord cr; + llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(type, cr)); + return CVTagRecord(std::move(cr)); + } + case LF_UNION: { + UnionRecord ur; + llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(type, ur)); + return CVTagRecord(std::move(ur)); + } + case LF_ENUM: { + EnumRecord er; + llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(type, er)); + return CVTagRecord(std::move(er)); + } + default: + llvm_unreachable("Unreachable!"); + } +} + +CVTagRecord::CVTagRecord(ClassRecord &&c) + : cvclass(std::move(c)), + m_kind(cvclass.Kind == TypeRecordKind::Struct ? Struct : Class) {} +CVTagRecord::CVTagRecord(UnionRecord &&u) + : cvunion(std::move(u)), m_kind(Union) {} +CVTagRecord::CVTagRecord(EnumRecord &&e) : cvenum(std::move(e)), m_kind(Enum) {} + PDB_SymType lldb_private::npdb::CVSymToPDBSym(SymbolKind kind) { switch (kind) { case S_COMPILE3: @@ -94,6 +126,8 @@ PDB_SymType lldb_private::npdb::CVTypeToPDBType(TypeLeafKind kind) { return PDB_SymType::Enum; case LF_PROCEDURE: return PDB_SymType::FunctionSig; + case LF_BITFIELD: + return PDB_SymType::BuiltinType; default: lldbassert(false && "Invalid type record kind!"); } @@ -306,6 +340,18 @@ bool lldb_private::npdb::IsForwardRefUdt(CVType cvt) { } } +bool lldb_private::npdb::IsTagRecord(llvm::codeview::CVType cvt) { + switch (cvt.kind()) { + case LF_CLASS: + case LF_STRUCTURE: + case LF_UNION: + case LF_ENUM: + return true; + default: + return false; + } +} + lldb::AccessType lldb_private::npdb::TranslateMemberAccess(MemberAccess access) { switch (access) { diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h index c5b5caee498..d9a0ed8f709 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -13,6 +13,7 @@ #include "lldb/lldb-enumerations.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include <tuple> @@ -21,6 +22,48 @@ namespace lldb_private { namespace npdb { +struct CVTagRecord { + enum Kind { Class, Struct, Union, Enum }; + + static CVTagRecord create(llvm::codeview::CVType type); + + Kind kind() const { return m_kind; } + + const llvm::codeview::TagRecord &asTag() const { + if (m_kind == Struct || m_kind == Class) + return cvclass; + if (m_kind == Enum) + return cvenum; + return cvunion; + } + + const llvm::codeview::ClassRecord &asClass() const { + assert(m_kind == Struct || m_kind == Class); + return cvclass; + } + + const llvm::codeview::EnumRecord &asEnum() const { + assert(m_kind == Enum); + return cvenum; + } + + const llvm::codeview::UnionRecord &asUnion() const { + assert(m_kind == Union); + return cvunion; + } + +private: + CVTagRecord(llvm::codeview::ClassRecord &&c); + CVTagRecord(llvm::codeview::UnionRecord &&u); + CVTagRecord(llvm::codeview::EnumRecord &&e); + Kind m_kind; + union { + llvm::codeview::ClassRecord cvclass; + llvm::codeview::EnumRecord cvenum; + llvm::codeview::UnionRecord cvunion; + }; +}; + struct SegmentOffset { SegmentOffset() = default; SegmentOffset(uint16_t s, uint32_t o) : segment(s), offset(o) {} @@ -56,6 +99,7 @@ inline bool IsValidRecord(const llvm::codeview::ProcRefSym &sym) { } bool IsForwardRefUdt(llvm::codeview::CVType cvt); +bool IsTagRecord(llvm::codeview::CVType cvt); lldb::AccessType TranslateMemberAccess(llvm::codeview::MemberAccess access); llvm::codeview::TypeIndex GetFieldListIndex(llvm::codeview::CVType cvt); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 676d2eb0213..f086e4d5b82 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -13,13 +13,16 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamBuffer.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" +#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" @@ -43,14 +46,14 @@ #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Demangle/MicrosoftDemangle.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" -#include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h" - #include "PdbSymUid.h" #include "PdbUtil.h" #include "UdtRecordCompleter.h" @@ -527,9 +530,60 @@ void SymbolFileNativePDB::InitializeObject() { 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); } +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, + llvm::DenseMap<TypeIndex, TypeIndex> &parents) + : index(index), parents(parents), parent(parent) {} + + PdbIndex &index; + llvm::DenseMap<TypeIndex, TypeIndex> &parents; + TypeIndex parent; + + llvm::Error visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Record) override { + parents[Record.Type] = parent; + CVType child = index.tpi().getType(Record.Type); + if (!IsForwardRefUdt(child)) + 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, m_parent_types); + llvm::Error error = visitMemberRecordStream(field_list.data(), process); + if (error) + llvm::consumeError(std::move(error)); + } +} + uint32_t SymbolFileNativePDB::GetNumCompileUnits() { const DbiModuleList &modules = m_index->dbi().modules(); uint32_t count = modules.getModuleCount(); @@ -730,16 +784,69 @@ lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) { 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()}; +} + +std::pair<clang::DeclContext *, std::string> +SymbolFileNativePDB::CreateDeclInfoForType(const TagRecord &record, + TypeIndex ti) { + 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}; + + 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}; +} + lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion( - PdbSymUid type_uid, llvm::StringRef name, size_t size, + PdbSymUid type_uid, const llvm::codeview::TagRecord &record, size_t size, clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) { - // Ignore unnamed-tag UDTs. - name = DropNameScope(name); - if (name.empty()) - return nullptr; - - clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl(); + const PdbTypeSymId &tid = type_uid.asTypeSym(); + TypeIndex ti(tid.index); + clang::DeclContext *decl_context = nullptr; + std::string uname; + std::tie(decl_context, uname) = CreateDeclInfoForType(record, ti); lldb::AccessType access = (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; @@ -749,8 +856,9 @@ lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion( metadata.SetIsDynamicCXXType(false); CompilerType ct = - m_clang->CreateRecordType(decl_context, access, name.str().c_str(), ttk, + m_clang->CreateRecordType(decl_context, access, uname.c_str(), ttk, lldb::eLanguageTypeC_plus_plus, &metadata); + lldbassert(ct.IsValid()); clang::CXXRecordDecl *record_decl = @@ -771,7 +879,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateClassStructUnion( // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE. Declaration decl; return std::make_shared<Type>(type_uid.toOpaqueId(), m_clang->GetSymbolFile(), - ConstString(name), size, nullptr, + ConstString(uname), size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, Type::eResolveStateForward); } @@ -782,14 +890,13 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid, clang::MSInheritanceAttr::Spelling inheritance = GetMSInheritance(m_index->tpi().typeCollection(), cr); - return CreateClassStructUnion(type_uid, cr.getName(), cr.getSize(), ttk, - inheritance); + return CreateClassStructUnion(type_uid, cr, cr.getSize(), ttk, inheritance); } lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid, const UnionRecord &ur) { return CreateClassStructUnion( - type_uid, ur.getName(), ur.getSize(), clang::TTK_Union, + type_uid, ur, ur.getSize(), clang::TTK_Union, clang::MSInheritanceAttr::Spelling::Keyword_single_inheritance); } diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index fd842b93e28..6d3e80bcb12 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -162,6 +162,11 @@ public: 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); @@ -180,10 +185,9 @@ private: const llvm::codeview::ArrayRecord &ar); lldb::TypeSP CreateProcedureType(PdbSymUid type_uid, const llvm::codeview::ProcedureRecord &pr); - lldb::TypeSP - CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size, - clang::TagTypeKind ttk, - clang::MSInheritanceAttr::Spelling inheritance); + lldb::TypeSP CreateClassStructUnion( + PdbSymUid type_uid, const llvm::codeview::TagRecord &record, size_t size, + clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance); lldb::FunctionSP GetOrCreateFunction(PdbSymUid func_uid, const SymbolContext &sc); @@ -209,6 +213,8 @@ private: llvm::DenseMap<clang::TagDecl *, DeclStatus> m_decl_to_status; llvm::DenseMap<lldb::user_id_t, clang::TagDecl *> m_uid_to_decl; + llvm::DenseMap<llvm::codeview::TypeIndex, llvm::codeview::TypeIndex> + m_parent_types; llvm::DenseMap<lldb::user_id_t, lldb::VariableSP> m_global_vars; llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions; |

