diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -323,6 +323,8 @@ // 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); + if (parent_qt.isNull()) + return {nullptr, ""}; context = clang::TagDecl::castToDeclContext(parent_qt->getAsTagDecl()); return {context, uname}; @@ -532,6 +534,8 @@ break; case PdbSymUidKind::Type: { clang::QualType qt = GetOrCreateType(uid.asTypeSym()); + if (qt.isNull()) + return llvm::None; if (auto *tag = qt->getAsTagDecl()) { result = tag; break; @@ -581,6 +585,8 @@ std::vector types = m_index.tpi().findRecordsByName(scope_name); while (!types.empty()) { clang::QualType qt = GetOrCreateType(types.back()); + if (qt.isNull()) + continue; clang::TagDecl *tag = qt->getAsTagDecl(); if (tag) return {clang::TagDecl::castToDeclContext(tag), std::string(uname)}; @@ -622,6 +628,8 @@ std::vector matches = m_index.tpi().findRecordsByName(qname); while (!matches.empty()) { clang::QualType qt = GetOrCreateType(matches.back()); + if (qt.isNull()) + continue; clang::TagDecl *tag = qt->getAsTagDecl(); if (tag) return clang::TagDecl::castToDeclContext(tag); @@ -700,6 +708,8 @@ } bool PdbAstBuilder::CompleteType(clang::QualType qt) { + if (qt.isNull()) + return false; clang::TagDecl *tag = qt->getAsTagDecl(); if (!tag) return false; @@ -767,6 +777,8 @@ if (ti.getSimpleMode() != SimpleTypeMode::Direct) { clang::QualType direct_type = GetOrCreateType(ti.makeDirect()); + if (direct_type.isNull()) + return {}; return m_clang.getASTContext().getPointerType(direct_type); } @@ -791,7 +803,8 @@ if (pointer.isPointerToMember()) { MemberPointerInfo mpi = pointer.getMemberInfo(); clang::QualType class_type = GetOrCreateType(mpi.ContainingType); - + if (class_type.isNull()) + return {}; return m_clang.getASTContext().getMemberPointerType( pointee_type, class_type.getTypePtr()); } @@ -835,6 +848,9 @@ clang::DeclContext *context = nullptr; std::string uname; std::tie(context, uname) = CreateDeclInfoForType(record, id.index); + if (!context) + return {}; + clang::TagTypeKind ttk = TranslateUdtKind(record); lldb::AccessType access = (ttk == clang::TTK_Class) ? lldb::eAccessPrivate : lldb::eAccessPublic; @@ -899,6 +915,8 @@ clang::DeclContext &scope) { VariableInfo var_info = GetVariableNameInfo(sym); clang::QualType qt = GetOrCreateType(var_info.type); + if (qt.isNull()) + return nullptr; clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration( &scope, OptionalClangModuleID(), var_info.name.str().c_str(), qt); @@ -947,6 +965,8 @@ PdbTypeSymId real_type_id{udt.Type, false}; clang::QualType qt = GetOrCreateType(real_type_id); + if (qt.isNull()) + return nullptr; std::string uname = std::string(DropNameScope(udt.Name)); @@ -1017,6 +1037,9 @@ } clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) { + if (type.index.isNoneType()) + return {}; + lldb::user_id_t uid = toOpaqueUid(type); auto iter = m_uid_to_type.find(uid); if (iter != m_uid_to_type.end()) @@ -1029,6 +1052,8 @@ // 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); + if (qt.isNull()) + return {}; m_uid_to_type[toOpaqueUid(type)] = qt; return qt; } @@ -1036,6 +1061,9 @@ // This is either a full decl, or a forward decl with no matching full decl // in the debug info. qt = CreateType(type); + if (qt.isNull()) + return {}; + m_uid_to_type[toOpaqueUid(type)] = qt; if (IsTagRecord(type, m_index.tpi())) { clang::TagDecl *tag = qt->getAsTagDecl(); @@ -1298,6 +1326,8 @@ PdbCompilandSymId param_uid(func_id.modi, record_offset); clang::QualType qt = GetOrCreateType(param_type); + if (qt.isNull()) + return; CompilerType param_type_ct = m_clang.GetType(qt); clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( @@ -1319,7 +1349,12 @@ clang::DeclContext *decl_context = nullptr; std::string uname; std::tie(decl_context, uname) = CreateDeclInfoForType(er, id.index); + if (!decl_context) + return {}; + clang::QualType underlying_type = GetOrCreateType(er.UnderlyingType); + if (underlying_type.isNull()) + return {}; Declaration declaration; CompilerType enum_ct = m_clang.CreateEnumerationType( @@ -1336,7 +1371,7 @@ clang::QualType element_type = GetOrCreateType(ar.ElementType); uint64_t element_size = GetSizeOfType({ar.ElementType}, m_index.tpi()); - if (element_size == 0) + if (element_type.isNull() || element_size == 0) return {}; uint64_t element_count = ar.Size / element_size; @@ -1364,10 +1399,14 @@ for (TypeIndex arg_index : arg_indices) { clang::QualType arg_type = GetOrCreateType(arg_index); + if (arg_type.isNull()) + continue; arg_types.push_back(ToCompilerType(arg_type)); } clang::QualType return_type = GetOrCreateType(return_type_idx); + if (return_type.isNull()) + return {}; llvm::Optional cc = TranslateCallingConvention(calling_convention); @@ -1418,7 +1457,7 @@ clang::DeclContext *context = nullptr; std::string uname; std::tie(context, uname) = CreateDeclInfoForType(tag.asTag(), tid.index); - if (!context->isNamespace()) + if (!context || !context->isNamespace()) continue; clang::NamespaceDecl *ns = llvm::cast(context); diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -726,6 +726,8 @@ PdbTypeSymId best_decl_id = full_decl_uid ? *full_decl_uid : type_id; clang::QualType qt = m_ast->GetOrCreateType(best_decl_id); + if (qt.isNull()) + return nullptr; TypeSP result = CreateType(best_decl_id, m_ast->ToCompilerType(qt)); if (!result) diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -67,7 +67,8 @@ m_ast_builder.clang().CreateBaseClassSpecifier( qt.getAsOpaquePtr(), TranslateMemberAccess(access), vtable_idx.hasValue(), udt_cvt.kind() == LF_CLASS); - lldbassert(base_spec); + if (!base_spec) + return {}; m_bases.push_back( std::make_pair(vtable_idx.getValueOr(0), std::move(base_spec))); @@ -80,6 +81,8 @@ MemberAttributes attrs) { clang::QualType method_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx)); + if (method_qt.isNull()) + return; m_ast_builder.CompleteType(method_qt); CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt); lldb::opaque_compiler_type_t derived_opaque_ty = m_derived_ct.GetOpaqueQualType(); @@ -106,6 +109,8 @@ clang::QualType base_qt = AddBaseClassForTypeIndex(base.Type, base.getAccess()); + if (base_qt.isNull()) + return llvm::Error::success(); auto decl = m_ast_builder.clang().GetAsCXXRecordDecl(base_qt.getAsOpaquePtr()); lldbassert(decl); @@ -137,6 +142,8 @@ CVMemberRecord &cvr, StaticDataMemberRecord &static_data_member) { clang::QualType member_type = m_ast_builder.GetOrCreateType(PdbTypeSymId(static_data_member.Type)); + if (member_type.isNull()) + return llvm::Error::success(); CompilerType member_ct = m_ast_builder.ToCompilerType(member_type); @@ -235,6 +242,8 @@ } clang::QualType member_qt = m_ast_builder.GetOrCreateType(PdbTypeSymId(ti)); + if (member_qt.isNull()) + return Error::success(); m_ast_builder.CompleteType(member_qt); lldb::AccessType access = TranslateMemberAccess(data_member.getAccess()); diff --git a/lldb/test/Shell/SymbolFile/NativePDB/missing-type.s b/lldb/test/Shell/SymbolFile/NativePDB/missing-type.s new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/NativePDB/missing-type.s @@ -0,0 +1,108 @@ +# clang-format off +# REQUIRES: lld, x86 + +# Test when type index is missing in FieldList. +# RUN: llvm-mc -triple=x86_64-windows-msvc --filetype=obj %s > %t.obj +# RUN: lld-link /debug:full /nodefaultlib /entry:main %t.obj /out:%t.exe /base:0x140000000 +# RUN: lldb-test symbols --find=type --name=S %t.exe | FileCheck %s + +# CHECK: name = "S", size = 4, compiler_type = {{.*}} struct S { +# CHECK-NEXT: } + + + + .text + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +.set @feat.00, 0 + .intel_syntax noprefix + .file "a.cpp" + .def main; + .scl 2; + .type 32; + .endef + .globl main # -- Begin function main + .p2align 4, 0x90 +main: # @main +.seh_proc main +# %bb.0: # %entry + sub rsp, 24 + .seh_stackalloc 24 + .seh_endprologue + mov dword ptr [rsp + 20], 0 + mov qword ptr [rsp + 8], rdx + mov dword ptr [rsp + 4], ecx +.Ltmp0: + mov eax, dword ptr [rsp] + add rsp, 24 + ret +.Ltmp1: +.Lfunc_end0: + .seh_endproc + # -- End function + .section .drectve,"yn" +.Ltmp25: + .section .debug$T,"dr" + .p2align 2 + .long 4 # Debug section magic + # Pointer (0x1000) + .short 0xa # Record length + .short 0x1002 # Record kind: LF_POINTER + .long 0x670 # PointeeType: char* + .long 0x1000c # Attrs: [ Type: Near64, Mode: Pointer, SizeOf: 8 ] + # ArgList (0x1001) + .short 0xe # Record length + .short 0x1201 # Record kind: LF_ARGLIST + .long 0x2 # NumArgs + .long 0x74 # Argument: int + .long 0x1000 # Argument: char** + # Procedure (0x1002) + .short 0xe # Record length + .short 0x1008 # Record kind: LF_PROCEDURE + .long 0x74 # ReturnType: int + .byte 0x0 # CallingConvention: NearC + .byte 0x0 # FunctionOptions + .short 0x2 # NumParameters + .long 0x1001 # ArgListType: (int, char**) + # FuncId (0x1003) + .short 0x12 # Record length + .short 0x1601 # Record kind: LF_FUNC_ID + .long 0x0 # ParentScope + .long 0x1002 # FunctionType: int (int, char**) + .asciz "main" # Name + .byte 243 + .byte 242 + .byte 241 + # Struct (0x1004) + .short 0x1e # Record length + .short 0x1505 # Record kind: LF_STRUCTURE + .short 0x0 # MemberCount + .short 0x280 # Properties ( ForwardReference (0x80) | HasUniqueName (0x200) ) + .long 0x0 # FieldList + .long 0x0 # DerivedFrom + .long 0x0 # VShape + .short 0x0 # SizeOf + .asciz "S" # Name + .asciz ".?AUS@@" # LinkageName + # FieldList (0x1005) + .short 0xe # Record length + .short 0x1203 # Record kind: LF_FIELDLIST + .short 0x150d # Member kind: DataMember ( LF_MEMBER ) + .short 0x3 # Attrs: Public + .long 0 # Type. It's intentionally written as 0 for testing. + .short 0x0 # FieldOffset + .asciz "x" # Name + # Struct (0x1006) + .short 0x1e # Record length + .short 0x1505 # Record kind: LF_STRUCTURE + .short 0x1 # MemberCount + .short 0x200 # Properties ( HasUniqueName (0x200) ) + .long 0x1005 # FieldList: + .long 0x0 # DerivedFrom + .long 0x0 # VShape + .short 0x4 # SizeOf + .asciz "S" # Name + .asciz ".?AUS@@" # LinkageName