[LLDB][NativePDB] Check for missing type info to avoid crash.

NativePDB often assumes that all debug info are available.
This is one step to make it more pervasive.

Differential Revision: https://reviews.llvm.org/D125844
This commit is contained in:
Zequan Wu 2022-05-17 18:23:35 -07:00
parent 835e09c4c3
commit 5c9f3ec4ad
4 changed files with 162 additions and 4 deletions

View File

@ -323,6 +323,8 @@ PdbAstBuilder::CreateDeclInfoForType(const TagRecord &record, TypeIndex ti) {
// 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 @@ llvm::Optional<CompilerDecl> PdbAstBuilder::GetOrCreateDeclForUid(PdbSymUid uid)
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 @@ PdbAstBuilder::CreateDeclInfoForUndecoratedName(llvm::StringRef name) {
std::vector<TypeIndex> 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 @@ PdbAstBuilder::GetParentDeclContextForSymbol(const CVSymbol &sym) {
std::vector<TypeIndex> 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 @@ clang::DeclContext *PdbAstBuilder::GetParentDeclContext(PdbSymUid uid) {
}
bool PdbAstBuilder::CompleteType(clang::QualType qt) {
if (qt.isNull())
return false;
clang::TagDecl *tag = qt->getAsTagDecl();
if (!tag)
return false;
@ -767,6 +777,8 @@ clang::QualType PdbAstBuilder::CreateSimpleType(TypeIndex ti) {
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 @@ clang::QualType PdbAstBuilder::CreatePointerType(const PointerRecord &pointer) {
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::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id,
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::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym,
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 @@ PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) {
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::CreateType(PdbTypeSymId type) {
}
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 @@ clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) {
// 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 @@ clang::QualType PdbAstBuilder::GetOrCreateType(PdbTypeSymId type) {
// 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 @@ void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id,
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::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id,
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 PdbAstBuilder::CreateArrayType(const ArrayRecord &ar) {
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 @@ clang::QualType PdbAstBuilder::CreateFunctionType(
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<clang::CallingConv> cc =
TranslateCallingConvention(calling_convention);
@ -1418,7 +1457,7 @@ void PdbAstBuilder::ParseAllNamespacesPlusChildrenOf(
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<clang::NamespaceDecl>(context);

View File

@ -726,6 +726,8 @@ 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);
if (qt.isNull())
return nullptr;
TypeSP result = CreateType(best_decl_id, m_ast->ToCompilerType(qt));
if (!result)

View File

@ -67,7 +67,8 @@ clang::QualType UdtRecordCompleter::AddBaseClassForTypeIndex(
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 @@ void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
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 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
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 @@ Error UdtRecordCompleter::visitKnownMember(
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 @@ Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
}
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());

View File

@ -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: <field list>
.long 0x0 # DerivedFrom
.long 0x0 # VShape
.short 0x4 # SizeOf
.asciz "S" # Name
.asciz ".?AUS@@" # LinkageName