#include "PdbAstBuilder.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/RecordName.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/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Demangle/MicrosoftDemangle.h" #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.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 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 (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 args) { if (args.empty()) return false; return args.back() == TypeIndex::None(); } static bool AnyScopesHaveTemplateParams(llvm::ArrayRef scopes) { for (llvm::ms_demangle::Node *n : scopes) { auto *idn = static_cast(n); if (idn->TemplateParams) return true; } return false; } static llvm::Optional 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 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(); } lldb_private::CompilerDeclContext PdbAstBuilder::GetTranslationUnitDecl() { return ToCompilerDeclContext(*m_clang.GetTranslationUnitDecl()); } std::pair PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { // FIXME: Move this to GetDeclContextContainingUID. if (!record.hasUniqueName()) return CreateDeclInfoForUndecoratedName(record.Name); llvm::ms_demangle::Demangler demangler; StringView sv(record.UniqueName.begin(), record.UniqueName.size()); llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv); if (demangler.Error) return {m_clang.GetTranslationUnitDecl(), std::string(record.UniqueName)}; llvm::ms_demangle::IdentifierNode *idn = ttn->QualifiedName->getUnqualifiedIdentifier(); std::string uname = idn->toString(llvm::ms_demangle::OF_NoTagSpecifier); llvm::ms_demangle::NodeArrayNode *name_components = ttn->QualifiedName->Components; llvm::ArrayRef 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, std::string(record.Name)}; for (llvm::ms_demangle::Node *scope : scopes) { auto *nii = static_cast(scope); std::string str = nii->toString(); context = GetOrCreateNamespaceDecl(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(); 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 = 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)); } // 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: case S_REGREL32: case S_LOCAL: return true; default: break; } return false; } static std::string RenderScopeList(llvm::ArrayRef nodes) { lldbassert(!nodes.empty()); std::string result = nodes.front()->toString(); nodes = nodes.drop_front(); while (!nodes.empty()) { result += "::"; result += nodes.front()->toString(llvm::ms_demangle::OF_NoTagSpecifier); nodes = nodes.drop_front(); } return result; } static llvm::Optional FindPublicSym(const SegmentOffset &addr, SymbolStream &syms, PublicsStream &publics) { llvm::FixedStreamArray addr_map = publics.getAddressMap(); auto iter = std::lower_bound( addr_map.begin(), addr_map.end(), addr, [&](const ulittle32_t &x, const SegmentOffset &y) { CVSymbol s1 = syms.readRecord(x); lldbassert(s1.kind() == S_PUB32); PublicSym32 p1; llvm::cantFail(SymbolDeserializer::deserializeAs(s1, p1)); if (p1.Segment < y.segment) return true; return p1.Offset < y.offset; }); if (iter == addr_map.end()) return llvm::None; CVSymbol sym = syms.readRecord(*iter); lldbassert(sym.kind() == S_PUB32); PublicSym32 p; llvm::cantFail(SymbolDeserializer::deserializeAs(sym, p)); if (p.Segment == addr.segment && p.Offset == addr.offset) return p; return llvm::None; } clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) { CVSymbol cvs = m_index.ReadSymbolRecord(id); if (isLocalVariableType(cvs.kind())) { 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 GetOrCreateVariableDecl(scope_id, 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); default: return nullptr; } } llvm::Optional PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) { if (clang::Decl *result = TryGetDecl(uid)) return ToCompilerDecl(*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 llvm::None; } default: return llvm::None; } m_uid_to_decl[toOpaqueUid(uid)] = result; return ToCompilerDecl(*result); } clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) { if (uid.kind() == PdbSymUidKind::CompilandSym) { if (uid.asCompilandSym().offset == 0) return FromCompilerDeclContext(GetTranslationUnitDecl()); } auto option = GetOrCreateDeclForUid(uid); if (!option) return nullptr; clang::Decl *decl = FromCompilerDecl(option.getValue()); if (!decl) return nullptr; return clang::Decl::castToDeclContext(decl); } std::pair PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) { MSVCUndecoratedNameParser parser(name); llvm::ArrayRef specs = parser.GetSpecifiers(); auto context = FromCompilerDeclContext(GetTranslationUnitDecl()); llvm::StringRef uname = specs.back().GetBaseName(); specs = specs.drop_back(); if (specs.empty()) return {context, std::string(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); while (!types.empty()) { clang::QualType qt = GetOrCreateType(types.back()); clang::TagDecl *tag = qt->getAsTagDecl(); if (tag) return {clang::TagDecl::castToDeclContext(tag), std::string(uname)}; types.pop_back(); } // If that fails, treat it as a series of namespaces. for (const MSVCUndecoratedNameSpecifier &spec : specs) { std::string ns_name = spec.GetBaseName().str(); context = GetOrCreateNamespaceDecl(ns_name.c_str(), *context); } return {context, std::string(uname)}; } clang::DeclContext * PdbAstBuilder::GetParentDeclContextForSymbol(const CVSymbol &sym) { if (!SymbolHasAddress(sym)) return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; SegmentOffset addr = GetSegmentAndOffset(sym); llvm::Optional pub = FindPublicSym(addr, m_index.symrecords(), m_index.publics()); if (!pub) return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first; llvm::ms_demangle::Demangler demangler; StringView name{pub->Name.begin(), pub->Name.size()}; llvm::ms_demangle::SymbolNode *node = demangler.parse(name); if (!node) return FromCompilerDeclContext(GetTranslationUnitDecl()); llvm::ArrayRef name_components{ node->Name->Components->Nodes, node->Name->Components->Count - 1}; if (!name_components.empty()) { // Render the current list of scope nodes as a fully qualified name, and // look it up in the debug info as a type name. If we find something, // this is a type (which may itself be prefixed by a namespace). If we // don't, this is a list of namespaces. std::string qname = RenderScopeList(name_components); std::vector matches = m_index.tpi().findRecordsByName(qname); while (!matches.empty()) { clang::QualType qt = GetOrCreateType(matches.back()); clang::TagDecl *tag = qt->getAsTagDecl(); if (tag) return clang::TagDecl::castToDeclContext(tag); matches.pop_back(); } } // It's not a type. It must be a series of namespaces. auto context = FromCompilerDeclContext(GetTranslationUnitDecl()); while (!name_components.empty()) { std::string ns = name_components.front()->toString(); context = GetOrCreateNamespaceDecl(ns.c_str(), *context); name_components = name_components.drop_front(); } return context; } 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 scope = FindSymbolScope(m_index, uid.asCompilandSym()); if (scope) return GetOrCreateDeclContextForUid(*scope); CVSymbol sym = m_index.ReadSymbolRecord(uid.asCompilandSym()); return GetParentDeclContextForSymbol(sym); } 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()) return FromCompilerDeclContext(GetTranslationUnitDecl()); return GetOrCreateDeclContextForUid(PdbTypeSymId(iter->second)); } case PdbSymUidKind::FieldListMember: // In this case the parent DeclContext is the one for the class that this // member is inside of. break; case PdbSymUidKind::GlobalSym: { // If this refers to a compiland symbol, just recurse in with that symbol. // The only other possibilities are S_CONSTANT and S_UDT, in which case we // need to parse the undecorated name to figure out the scope, then look // 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()); switch (global.kind()) { case SymbolKind::S_GDATA32: case SymbolKind::S_LDATA32: return GetParentDeclContextForSymbol(global); case SymbolKind::S_PROCREF: case SymbolKind::S_LPROCREF: { ProcRefSym ref{global.kind()}; llvm::cantFail( SymbolDeserializer::deserializeAs(global, ref)); PdbCompilandSymId cu_sym_id{ref.modi(), ref.SymOffset}; return GetParentDeclContext(cu_sym_id); } case SymbolKind::S_CONSTANT: case SymbolKind::S_UDT: return CreateDeclInfoForUndecoratedName(getSymbolName(global)).first; default: break; } break; } default: break; } return FromCompilerDeclContext(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); TypeSystemClang::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); 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); // This can happen for pointers to LF_VTSHAPE records, which we shouldn't // create in the AST. if (pointee_type.isNull()) return {}; 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 (unmodified_type.isNull()) return {}; 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 *context = nullptr; std::string uname; std::tie(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(context, OptionalClangModuleID(), access, uname, ttk, lldb::eLanguageTypeC_plus_plus, &metadata); lldbassert(ct.IsValid()); TypeSystemClang::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()); TypeSystemClang::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(const char *name, clang::DeclContext &context) { return m_clang.GetUniqueNamespaceDeclaration( IsAnonymousNamespaceName(name) ? nullptr : name, &context, OptionalClangModuleID()); } clang::BlockDecl * PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) { if (clang::Decl *decl = TryGetDecl(block_id)) return llvm::dyn_cast(decl); clang::DeclContext *scope = GetParentDeclContext(block_id); clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope, OptionalClangModuleID()); m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl}); DeclStatus status; status.resolved = true; status.uid = toOpaqueUid(block_id); m_decl_to_status.insert({block_decl, status}); return block_decl; } clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym, clang::DeclContext &scope) { VariableInfo var_info = GetVariableNameInfo(sym); clang::QualType qt = GetOrCreateType(var_info.type); clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration( &scope, OptionalClangModuleID(), var_info.name.str().c_str(), qt); m_uid_to_decl[toOpaqueUid(uid)] = var_decl; DeclStatus status; status.resolved = true; status.uid = toOpaqueUid(uid); m_decl_to_status.insert({var_decl, status}); return var_decl; } clang::VarDecl * PdbAstBuilder::GetOrCreateVariableDecl(PdbCompilandSymId scope_id, PdbCompilandSymId var_id) { if (clang::Decl *decl = TryGetDecl(var_id)) return llvm::dyn_cast(decl); clang::DeclContext *scope = GetOrCreateDeclContextForUid(scope_id); CVSymbol sym = m_index.ReadSymbolRecord(var_id); return CreateVariableDecl(PdbSymUid(var_id), sym, *scope); } 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); auto context = FromCompilerDeclContext(GetTranslationUnitDecl()); return CreateVariableDecl(PdbSymUid(var_id), sym, *context); } clang::TypedefNameDecl * PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { if (clang::Decl *decl = TryGetDecl(id)) return llvm::dyn_cast(decl); CVSymbol sym = m_index.ReadSymbolRecord(id); lldbassert(sym.kind() == S_UDT); UDTSym udt = llvm::cantFail(SymbolDeserializer::deserializeAs(sym)); clang::DeclContext *scope = GetParentDeclContext(id); PdbTypeSymId real_type_id{udt.Type, false}; clang::QualType qt = GetOrCreateType(real_type_id); std::string uname = std::string(DropNameScope(udt.Name)); CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(), ToCompilerDeclContext(*scope), 0); clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct); DeclStatus status; status.resolved = true; status.uid = toOpaqueUid(id); m_decl_to_status.insert({tnd, status}); return tnd; } 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(cvt, modifier)); return CreateModifierType(modifier); } if (cvt.kind() == LF_POINTER) { PointerRecord pointer; llvm::cantFail( TypeDeserializer::deserializeAs(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(cvt, ar)); return CreateArrayType(ar); } if (cvt.kind() == LF_PROCEDURE) { ProcedureRecord pr; llvm::cantFail(TypeDeserializer::deserializeAs(cvt, pr)); return CreateFunctionType(pr.ArgumentList, pr.ReturnType, pr.CallConv); } if (cvt.kind() == LF_MFUNCTION) { MemberFunctionRecord mfr; llvm::cantFail( TypeDeserializer::deserializeAs(cvt, mfr)); return CreateFunctionType(mfr.ArgumentList, mfr.ReturnType, mfr.CallConv); } 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(decl); clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id)); std::string context_name; if (clang::NamespaceDecl *ns = llvm::dyn_cast(parent)) { context_name = ns->getQualifiedNameAsString(); } else if (clang::TagDecl *tag = llvm::dyn_cast(parent)) { context_name = tag->getQualifiedNameAsString(); } CVSymbol cvs = m_index.ReadSymbolRecord(func_id); ProcSym proc(static_cast(cvs.kind())); llvm::cantFail(SymbolDeserializer::deserializeAs(cvs, proc)); PdbTypeSymId type_id(proc.FunctionType); clang::QualType qt = GetOrCreateType(type_id); if (qt.isNull()) return nullptr; clang::StorageClass storage = clang::SC_None; if (proc.Kind == SymbolRecordKind::ProcSym) storage = clang::SC_Static; const clang::FunctionProtoType *func_type = llvm::dyn_cast(qt); CompilerType func_ct = ToCompilerType(qt); llvm::StringRef proc_name = proc.Name; proc_name.consume_front(context_name); proc_name.consume_front("::"); clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( parent, OptionalClangModuleID(), proc_name, func_ct, storage, false); lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; DeclStatus status; status.resolved = true; status.uid = toOpaqueUid(func_id); m_decl_to_status.insert({function_decl, status}); 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 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(sym, reg)); param_type = reg.Type; param_name = reg.Name; break; } case S_REGISTER: { RegisterSym reg(SymbolRecordKind::RegisterSym); cantFail(SymbolDeserializer::deserializeAs(sym, reg)); param_type = reg.Index; param_name = reg.Name; break; } case S_LOCAL: { LocalSym local(SymbolRecordKind::LocalSym); cantFail(SymbolDeserializer::deserializeAs(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.GetType(qt); clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( &function_decl, OptionalClangModuleID(), param_name.str().c_str(), param_type_ct, clang::SC_None, true); 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, OptionalClangModuleID(), declaration, ToCompilerType(underlying_type), er.isScoped()); TypeSystemClang::StartTagDeclarationDefinition(enum_ct); TypeSystemClang::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::CreateFunctionType( TypeIndex args_type_idx, TypeIndex return_type_idx, llvm::codeview::CallingConvention calling_convention) { TpiStream &stream = m_index.tpi(); CVType args_cvt = stream.getType(args_type_idx); ArgListRecord args; llvm::cantFail( TypeDeserializer::deserializeAs(args_cvt, args)); llvm::ArrayRef arg_indices = llvm::makeArrayRef(args.ArgIndices); bool is_variadic = IsCVarArgsFunction(arg_indices); if (is_variadic) arg_indices = arg_indices.drop_back(); std::vector 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(return_type_idx); llvm::Optional cc = TranslateCallingConvention(calling_convention); 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()); } static bool isTagDecl(clang::DeclContext &context) { return !!llvm::dyn_cast(&context); } static bool isFunctionDecl(clang::DeclContext &context) { return !!llvm::dyn_cast(&context); } static bool isBlockDecl(clang::DeclContext &context) { return !!llvm::dyn_cast(&context); } void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf( llvm::Optional parent) { TypeIndex ti{m_index.tpi().TypeIndexBegin()}; for (const CVType &cvt : m_index.tpi().typeArray()) { PdbTypeSymId tid{ti}; ++ti; if (!IsTagRecord(cvt)) continue; CVTagRecord tag = CVTagRecord::create(cvt); if (!parent.hasValue()) { clang::QualType qt = GetOrCreateType(tid); CompleteType(qt); continue; } // Call CreateDeclInfoForType unconditionally so that the namespace info // gets created. But only call CreateRecordType if the namespace name // matches. clang::DeclContext *context = nullptr; std::string uname; std::tie(context, uname) = CreateDeclInfoForType(tag.asTag(), tid.index); if (!context->isNamespace()) continue; clang::NamespaceDecl *ns = llvm::dyn_cast(context); std::string actual_ns = ns->getQualifiedNameAsString(); if (llvm::StringRef(actual_ns).startswith(*parent)) { clang::QualType qt = GetOrCreateType(tid); CompleteType(qt); continue; } } uint32_t module_count = m_index.dbi().modules().getModuleCount(); for (uint16_t modi = 0; modi < module_count; ++modi) { CompilandIndexItem &cii = m_index.compilands().GetOrCreateCompiland(modi); const CVSymbolArray &symbols = cii.m_debug_stream.getSymbolArray(); auto iter = symbols.begin(); while (iter != symbols.end()) { PdbCompilandSymId sym_id{modi, iter.offset()}; switch (iter->kind()) { case S_GPROC32: case S_LPROC32: GetOrCreateFunctionDecl(sym_id); iter = symbols.at(getScopeEndOffset(*iter)); break; case S_GDATA32: case S_GTHREAD32: case S_LDATA32: case S_LTHREAD32: GetOrCreateVariableDecl(PdbCompilandSymId(modi, 0), sym_id); ++iter; break; default: ++iter; continue; } } } } static CVSymbolArray skipFunctionParameters(clang::Decl &decl, const CVSymbolArray &symbols) { clang::FunctionDecl *func_decl = llvm::dyn_cast(&decl); if (!func_decl) return symbols; unsigned int params = func_decl->getNumParams(); if (params == 0) return symbols; CVSymbolArray result = symbols; while (!result.empty()) { if (params == 0) return result; CVSymbol sym = *result.begin(); result.drop_front(); if (!isLocalVariableType(sym.kind())) continue; --params; } return result; } void PdbAstBuilder::ParseBlockChildren(PdbCompilandSymId block_id) { CVSymbol sym = m_index.ReadSymbolRecord(block_id); lldbassert(sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32 || sym.kind() == S_BLOCK32); CompilandIndexItem &cii = m_index.compilands().GetOrCreateCompiland(block_id.modi); CVSymbolArray symbols = cii.m_debug_stream.getSymbolArrayForScope(block_id.offset); // Function parameters should already have been created when the function was // parsed. if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) symbols = skipFunctionParameters(*m_uid_to_decl[toOpaqueUid(block_id)], symbols); auto begin = symbols.begin(); while (begin != symbols.end()) { PdbCompilandSymId child_sym_id(block_id.modi, begin.offset()); GetOrCreateSymbolForId(child_sym_id); if (begin->kind() == S_BLOCK32) { ParseBlockChildren(child_sym_id); begin = symbols.at(getScopeEndOffset(*begin)); } ++begin; } } void PdbAstBuilder::ParseDeclsForSimpleContext(clang::DeclContext &context) { clang::Decl *decl = clang::Decl::castFromDeclContext(&context); lldbassert(decl); auto iter = m_decl_to_status.find(decl); lldbassert(iter != m_decl_to_status.end()); if (auto *tag = llvm::dyn_cast(&context)) { CompleteTagDecl(*tag); return; } if (isFunctionDecl(context) || isBlockDecl(context)) { PdbCompilandSymId block_id = PdbSymUid(iter->second.uid).asCompilandSym(); ParseBlockChildren(block_id); } } void PdbAstBuilder::ParseDeclsForContext(clang::DeclContext &context) { // Namespaces aren't explicitly represented in the debug info, and the only // way to parse them is to parse all type info, demangling every single type // and trying to reconstruct the DeclContext hierarchy this way. Since this // is an expensive operation, we have to special case it so that we do other // work (such as parsing the items that appear within the namespaces) at the // same time. if (context.isTranslationUnit()) { ParseAllNamespacesPlusChildrenOf(llvm::None); return; } if (context.isNamespace()) { clang::NamespaceDecl &ns = *llvm::dyn_cast(&context); std::string qname = ns.getQualifiedNameAsString(); ParseAllNamespacesPlusChildrenOf(llvm::StringRef{qname}); return; } if (isTagDecl(context) || isFunctionDecl(context) || isBlockDecl(context)) { ParseDeclsForSimpleContext(context); return; } } CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) { return m_clang.GetCompilerDecl(&decl); } CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) { return {&m_clang, qt.getAsOpaquePtr()}; } CompilerDeclContext PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) { return m_clang.CreateDeclContext(&context); } clang::Decl * PdbAstBuilder::FromCompilerDecl(CompilerDecl decl) { return ClangUtil::GetDecl(decl); } clang::DeclContext * PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) { return static_cast(context.GetOpaqueDeclContext()); } void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); }