#include "PdbAstBuilder.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Demangle/MicrosoftDemangle.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" #include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" #include "PdbUtil.h" #include "UdtRecordCompleter.h" using namespace lldb_private; using namespace lldb_private::npdb; using namespace llvm::codeview; using namespace llvm::pdb; static llvm::Optional 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 ClangASTContext &GetClangASTContext(ObjectFile &obj) { TypeSystem *ts = obj.GetModule()->GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); lldbassert(ts); return static_cast(*ts); } 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 GetNestedTagRecord(const NestedTypeRecord &Record, const CVTagRecord &parent, TpiStream &tpi) { // An LF_NESTTYPE is essentially a nested typedef / using declaration, but it // is also used to indicate the primary definition of a nested class. That is // to say, if you have: // struct A { // struct B {}; // using C = B; // }; // Then in the debug info, this will appear as: // LF_STRUCTURE `A::B` [type index = N] // LF_STRUCTURE `A` // LF_NESTTYPE [name = `B`, index = N] // LF_NESTTYPE [name = `C`, index = N] // In order to accurately reconstruct the decl context hierarchy, we need to // know which ones are actual definitions and which ones are just aliases. // If it's a simple type, then this is something like `using foo = int`. if (Record.Type.isSimple()) return llvm::None; CVType cvt = tpi.getType(Record.Type); if (!IsTagRecord(cvt)) return llvm::None; // If it's an inner definition, then treat whatever name we have here as a // single component of a mangled name. So we can inject it into the parent's // mangled name to see if it matches. CVTagRecord child = CVTagRecord::create(cvt); std::string qname = parent.asTag().getUniqueName(); if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4) return llvm::None; // qname[3] is the tag type identifier (struct, class, union, etc). Since the // inner tag type is not necessarily the same as the outer tag type, re-write // it to match the inner tag type. qname[3] = child.asTag().getUniqueName()[3]; std::string piece; 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); } PdbAstBuilder::PdbAstBuilder(ObjectFile &obj, PdbIndex &index) : m_index(index), m_clang(GetClangASTContext(obj)) { BuildParentMap(); } clang::DeclContext &PdbAstBuilder::GetTranslationUnitDecl() { return *m_clang.GetTranslationUnitDecl(); } std::pair PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) { // FIXME: Move this to GetDeclContextContainingUID. llvm::ms_demangle::Demangler demangler; StringView sv(record.UniqueName.begin(), record.UniqueName.size()); llvm::ms_demangle::TagTypeNode *ttn = demangler.parseTagUniqueName(sv); llvm::ms_demangle::IdentifierNode *idn = ttn->QualifiedName->getUnqualifiedIdentifier(); std::string uname = idn->toString(); llvm::ms_demangle::NodeArrayNode *name_components = ttn->QualifiedName->Components; llvm::ArrayRef scopes(name_components->Nodes, name_components->Count - 1); clang::DeclContext *context = m_clang.GetTranslationUnitDecl(); // If this type doesn't have a parent type in the debug info, then the best we // can do is to say that it's either a series of namespaces (if the scope is // non-empty), or the translation unit (if the scope is empty). auto parent_iter = m_parent_types.find(ti); if (parent_iter == m_parent_types.end()) { if (scopes.empty()) return {context, uname}; // If there is no parent in the debug info, but some of the scopes have // template params, then this is a case of bad debug info. See, for // example, llvm.org/pr39607. We don't want to create an ambiguity between // a NamespaceDecl and a CXXRecordDecl, so instead we create a class at // global scope with the fully qualified name. if (AnyScopesHaveTemplateParams(scopes)) return {context, record.Name}; for (llvm::ms_demangle::Node *scope : scopes) { auto *nii = static_cast(scope); std::string str = nii->toString(); context = m_clang.GetUniqueNamespaceDeclaration(str.c_str(), context); } return {context, uname}; } // Otherwise, all we need to do is get the parent type of this type and // recurse into our lazy type creation / AST reconstruction logic to get an // LLDB TypeSP for the parent. This will cause the AST to automatically get // the right DeclContext created for any parent. clang::QualType parent_qt = GetOrCreateType(parent_iter->second); context = clang::TagDecl::castToDeclContext(parent_qt->getAsTagDecl()); return {context, uname}; } void PdbAstBuilder::BuildParentMap() { LazyRandomTypeCollection &types = m_index.tpi().typeCollection(); for (auto ti = types.getFirst(); ti; ti = types.getNext(*ti)) { CVType type = types.getType(*ti); if (!IsTagRecord(type)) continue; CVTagRecord tag = CVTagRecord::create(type); // We're looking for LF_NESTTYPE records in the field list, so ignore // forward references (no field list), and anything without a nested class // (since there won't be any LF_NESTTYPE records). if (tag.asTag().isForwardRef() || !tag.asTag().containsNestedClass()) continue; struct ProcessTpiStream : public TypeVisitorCallbacks { ProcessTpiStream(PdbIndex &index, TypeIndex parent, const CVTagRecord &parent_cvt, llvm::DenseMap &parents) : index(index), parents(parents), parent(parent), parent_cvt(parent_cvt) {} PdbIndex &index; llvm::DenseMap &parents; TypeIndex parent; const CVTagRecord &parent_cvt; llvm::Error visitKnownMember(CVMemberRecord &CVR, NestedTypeRecord &Record) override { llvm::Optional tag = GetNestedTagRecord(Record, parent_cvt, index.tpi()); if (!tag) return llvm::ErrorSuccess(); parents[Record.Type] = parent; if (!tag->asTag().isForwardRef()) return llvm::ErrorSuccess(); llvm::Expected full_decl = index.tpi().findFullDeclForForwardRef(Record.Type); if (!full_decl) { llvm::consumeError(full_decl.takeError()); return llvm::ErrorSuccess(); } parents[*full_decl] = parent; return llvm::ErrorSuccess(); } }; CVType field_list = m_index.tpi().getType(tag.asTag().FieldList); ProcessTpiStream process(m_index, *ti, tag, m_parent_types); llvm::Error error = visitMemberRecordStream(field_list.data(), process); if (error) llvm::consumeError(std::move(error)); } } clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) { CVSymbol cvs = m_index.ReadSymbolRecord(id); switch (cvs.kind()) { case S_GPROC32: case S_LPROC32: return GetOrCreateFunctionDecl(id); case S_GDATA32: case S_LDATA32: case S_GTHREAD32: case S_CONSTANT: // global variable return nullptr; case S_BLOCK32: return GetOrCreateBlockDecl(id); case S_REGISTER: case S_REGREL32: case S_LOCAL: { clang::DeclContext *scope = GetParentDeclContext(id); clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope); PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid); return GetOrCreateLocalVariableDecl(scope_id, id); } default: return nullptr; } } clang::Decl *PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid) { if (clang::Decl *result = TryGetDecl(uid)) return result; clang::Decl *result = nullptr; switch (uid.kind()) { case PdbSymUidKind::CompilandSym: result = GetOrCreateSymbolForId(uid.asCompilandSym()); break; case PdbSymUidKind::Type: { clang::QualType qt = GetOrCreateType(uid.asTypeSym()); if (auto *tag = qt->getAsTagDecl()) { result = tag; break; } return nullptr; } default: return nullptr; } m_uid_to_decl[toOpaqueUid(uid)] = result; return result; } clang::DeclContext *PdbAstBuilder::GetOrCreateDeclContextForUid(PdbSymUid uid) { clang::Decl *decl = GetOrCreateDeclForUid(uid); if (!decl) return nullptr; return clang::Decl::castToDeclContext(decl); } clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) { // We must do this *without* calling GetOrCreate on the current uid, as // that would be an infinite recursion. switch (uid.kind()) { case PdbSymUidKind::CompilandSym: { llvm::Optional scope = FindSymbolScope(m_index, uid.asCompilandSym()); if (!scope) return &GetTranslationUnitDecl(); return GetOrCreateDeclContextForUid(*scope); } case PdbSymUidKind::Type: // It could be a namespace, class, or global. We don't support nested // functions yet. Anyway, we just need to consult the parent type map. break; case PdbSymUidKind::FieldListMember: // In this case the parent DeclContext is the one for the class that this // member is inside of. break; default: break; } return &GetTranslationUnitDecl(); } bool PdbAstBuilder::CompleteType(clang::QualType qt) { clang::TagDecl *tag = qt->getAsTagDecl(); if (!tag) return false; return CompleteTagDecl(*tag); } bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) { // If this is not in our map, it's an error. auto status_iter = m_decl_to_status.find(&tag); lldbassert(status_iter != m_decl_to_status.end()); // If it's already complete, just return. DeclStatus &status = status_iter->second; if (status.resolved) return true; PdbTypeSymId type_id = PdbSymUid(status.uid).asTypeSym(); lldbassert(IsTagRecord(type_id, m_index.tpi())); clang::QualType tag_qt = m_clang.getASTContext()->getTypeDeclType(&tag); ClangASTContext::SetHasExternalStorage(tag_qt.getAsOpaquePtr(), false); TypeIndex tag_ti = type_id.index; CVType cvt = m_index.tpi().getType(tag_ti); if (cvt.kind() == LF_MODIFIER) tag_ti = LookThroughModifierRecord(cvt); PdbTypeSymId best_ti = GetBestPossibleDecl(tag_ti, m_index.tpi()); cvt = m_index.tpi().getType(best_ti.index); lldbassert(IsTagRecord(cvt)); if (IsForwardRefUdt(cvt)) { // If we can't find a full decl for this forward ref anywhere in the debug // info, then we have no way to complete it. return false; } TypeIndex field_list_ti = GetFieldListIndex(cvt); CVType field_list_cvt = m_index.tpi().getType(field_list_ti); if (field_list_cvt.kind() != LF_FIELDLIST) return false; // Visit all members of this class, then perform any finalization necessary // to complete the class. CompilerType ct = ToCompilerType(tag_qt); UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index.tpi()); auto error = llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer); completer.complete(); status.resolved = true; if (!error) return true; llvm::consumeError(std::move(error)); return false; } clang::QualType PdbAstBuilder::CreateSimpleType(TypeIndex ti) { if (ti == TypeIndex::NullptrT()) return GetBasicType(lldb::eBasicTypeNullPtr); if (ti.getSimpleMode() != SimpleTypeMode::Direct) { clang::QualType direct_type = GetOrCreateType(ti.makeDirect()); return m_clang.getASTContext()->getPointerType(direct_type); } if (ti.getSimpleKind() == SimpleTypeKind::NotTranslated) return {}; lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind()); if (bt == lldb::eBasicTypeInvalid) return {}; return GetBasicType(bt); } clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) { clang::QualType pointee_type = GetOrCreateType(pointer.ReferentType); if (pointer.isPointerToMember()) { MemberPointerInfo mpi = pointer.getMemberInfo(); clang::QualType class_type = GetOrCreateType(mpi.ContainingType); return m_clang.getASTContext()->getMemberPointerType( pointee_type, class_type.getTypePtr()); } clang::QualType pointer_type; if (pointer.getMode() == PointerMode::LValueReference) pointer_type = m_clang.getASTContext()->getLValueReferenceType(pointee_type); else if (pointer.getMode() == PointerMode::RValueReference) pointer_type = m_clang.getASTContext()->getRValueReferenceType(pointee_type); else pointer_type = m_clang.getASTContext()->getPointerType(pointee_type); if ((pointer.getOptions() & PointerOptions::Const) != PointerOptions::None) pointer_type.addConst(); if ((pointer.getOptions() & PointerOptions::Volatile) != PointerOptions::None) pointer_type.addVolatile(); if ((pointer.getOptions() & PointerOptions::Restrict) != PointerOptions::None) pointer_type.addRestrict(); return pointer_type; } clang::QualType PdbAstBuilder::CreateModifierType(const ModifierRecord &modifier) { clang::QualType unmodified_type = GetOrCreateType(modifier.ModifiedType); if ((modifier.Modifiers & ModifierOptions::Const) != ModifierOptions::None) unmodified_type.addConst(); if ((modifier.Modifiers & ModifierOptions::Volatile) != ModifierOptions::None) unmodified_type.addVolatile(); return unmodified_type; } clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, const TagRecord &record) { clang::DeclContext *decl_context = nullptr; std::string uname; std::tie(decl_context, uname) = CreateDeclInfoForType(record, id.index); clang::TagTypeKind ttk = TranslateUdtKind(record); lldb::AccessType access = (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; ClangASTMetadata metadata; metadata.SetUserID(toOpaqueUid(id)); metadata.SetIsDynamicCXXType(false); CompilerType ct = m_clang.CreateRecordType(decl_context, access, uname.c_str(), ttk, lldb::eLanguageTypeC_plus_plus, &metadata); lldbassert(ct.IsValid()); ClangASTContext::StartTagDeclarationDefinition(ct); // Even if it's possible, don't complete it at this point. Just mark it // forward resolved, and if/when LLDB needs the full definition, it can // ask us. clang::QualType result = clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); ClangASTContext::SetHasExternalStorage(result.getAsOpaquePtr(), true); return result; } clang::Decl *PdbAstBuilder::TryGetDecl(PdbSymUid uid) const { auto iter = m_uid_to_decl.find(toOpaqueUid(uid)); if (iter != m_uid_to_decl.end()) return iter->second; return nullptr; } clang::NamespaceDecl * PdbAstBuilder::GetOrCreateNamespaceDecl(llvm::StringRef name, clang::DeclContext &context) { return m_clang.GetUniqueNamespaceDeclaration(name.str().c_str(), &context); } clang::BlockDecl * PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) { if (clang::Decl *decl = TryGetDecl(block_id)) return llvm::dyn_cast(decl); clang::DeclContext *scope = GetParentDeclContext(block_id); clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope); m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl}); return block_decl; } clang::VarDecl * PdbAstBuilder::GetOrCreateLocalVariableDecl(PdbCompilandSymId scope_id, PdbCompilandSymId var_id) { if (clang::Decl *decl = TryGetDecl(var_id)) return llvm::dyn_cast(decl); clang::DeclContext *scope = GetOrCreateDeclContextForUid(scope_id); CVSymbol var = m_index.ReadSymbolRecord(var_id); VariableInfo var_info = GetVariableNameInfo(var); clang::QualType qt = GetOrCreateType(var_info.type); clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration(scope, var_info.name.str().c_str(), qt); m_uid_to_decl[toOpaqueUid(var_id)] = var_decl; return var_decl; } clang::QualType PdbAstBuilder::GetBasicType(lldb::BasicType type) { CompilerType ct = m_clang.GetBasicType(type); return clang::QualType::getFromOpaquePtr(ct.GetOpaqueQualType()); } clang::QualType PdbAstBuilder::CreateType(PdbTypeSymId type) { if (type.index.isSimple()) return CreateSimpleType(type.index); CVType cvt = m_index.tpi().getType(type.index); if (cvt.kind() == LF_MODIFIER) { ModifierRecord modifier; llvm::cantFail( TypeDeserializer::deserializeAs(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 CreateProcedureType(pr); } return {}; } clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) { lldb::user_id_t uid = toOpaqueUid(type); auto iter = m_uid_to_type.find(uid); if (iter != m_uid_to_type.end()) return iter->second; PdbTypeSymId best_type = GetBestPossibleDecl(type, m_index.tpi()); clang::QualType qt; if (best_type.index != type.index) { // This is a forward decl. Call GetOrCreate on the full decl, then map the // forward decl id to the full decl QualType. clang::QualType qt = GetOrCreateType(best_type); m_uid_to_type[toOpaqueUid(type)] = qt; return qt; } // This is either a full decl, or a forward decl with no matching full decl // in the debug info. qt = CreateType(type); m_uid_to_type[toOpaqueUid(type)] = qt; if (IsTagRecord(type, m_index.tpi())) { clang::TagDecl *tag = qt->getAsTagDecl(); lldbassert(m_decl_to_status.count(tag) == 0); DeclStatus &status = m_decl_to_status[tag]; status.uid = uid; status.resolved = false; } return qt; } clang::FunctionDecl * PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { if (clang::Decl *decl = TryGetDecl(func_id)) return llvm::dyn_cast(decl); clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id)); 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); 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); clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( parent, proc.Name.str().c_str(), func_ct, storage, false); lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams()); return function_decl; } void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, clang::FunctionDecl &function_decl, uint32_t param_count) { CompilandIndexItem *cii = m_index.compilands().GetCompiland(func_id.modi); CVSymbolArray scope = cii->m_debug_stream.getSymbolArrayForScope(func_id.offset); auto begin = scope.begin(); auto end = scope.end(); std::vector 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, qt.getAsOpaquePtr()); clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( &function_decl, param_name.str().c_str(), param_type_ct, clang::SC_None); lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); m_uid_to_decl[toOpaqueUid(param_uid)] = param; params.push_back(param); --param_count; } if (!params.empty()) m_clang.SetFunctionParameters(&function_decl, params.data(), params.size()); } clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, const EnumRecord &er) { clang::DeclContext *decl_context = nullptr; std::string uname; std::tie(decl_context, uname) = CreateDeclInfoForType(er, id.index); clang::QualType underlying_type = GetOrCreateType(er.UnderlyingType); Declaration declaration; CompilerType enum_ct = m_clang.CreateEnumerationType( uname.c_str(), decl_context, declaration, ToCompilerType(underlying_type), er.isScoped()); ClangASTContext::StartTagDeclarationDefinition(enum_ct); ClangASTContext::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); return clang::QualType::getFromOpaquePtr(enum_ct.GetOpaqueQualType()); } clang::QualType PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) { clang::QualType element_type = GetOrCreateType(ar.ElementType); uint64_t element_count = ar.Size / GetSizeOfType({ar.ElementType}, m_index.tpi()); CompilerType array_ct = m_clang.CreateArrayType(ToCompilerType(element_type), element_count, false); return clang::QualType::getFromOpaquePtr(array_ct.GetOpaqueQualType()); } clang::QualType PdbAstBuilder::CreateProcedureType(const ProcedureRecord &proc) { TpiStream &stream = m_index.tpi(); CVType args_cvt = stream.getType(proc.ArgumentList); ArgListRecord args; llvm::cantFail( TypeDeserializer::deserializeAs(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(proc.ReturnType); llvm::Optional cc = TranslateCallingConvention(proc.CallConv); if (!cc) return {}; CompilerType return_ct = ToCompilerType(return_type); CompilerType func_sig_ast_type = m_clang.CreateFunctionType( return_ct, arg_types.data(), arg_types.size(), is_variadic, 0, *cc); return clang::QualType::getFromOpaquePtr( func_sig_ast_type.GetOpaqueQualType()); } CompilerDecl PdbAstBuilder::ToCompilerDecl(clang::Decl &decl) { return {&m_clang, &decl}; } CompilerType PdbAstBuilder::ToCompilerType(clang::QualType qt) { return {&m_clang, qt.getAsOpaquePtr()}; } CompilerDeclContext PdbAstBuilder::ToCompilerDeclContext(clang::DeclContext &context) { return {&m_clang, &context}; } void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); }