-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP][lldb][DWARFASTParserClang] Eagerly search definitions for Objective-C classes #119860
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1671,43 +1671,84 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
attrs.is_forward_declaration = true; | ||
} | ||
|
||
DWARFDIE def_die; | ||
if (attrs.is_forward_declaration && cu_language == eLanguageTypeObjC) { | ||
def_die = dwarf->FindDefinitionDIE(die); | ||
|
||
if (!def_die) { | ||
SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); | ||
if (debug_map_symfile) { | ||
// We weren't able to find a full declaration in this DWARF, | ||
// see if we have a declaration anywhere else... | ||
def_die = debug_map_symfile->FindDefinitionDIE(die); | ||
} | ||
} | ||
|
||
if (log) { | ||
dwarf->GetObjectFile()->GetModule()->LogMessage( | ||
log, | ||
"SymbolFileDWARF({0:p}) - {1:x16}}: {2} ({3}) type \"{4}\" is a " | ||
"forward declaration, complete DIE is {5}", | ||
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag), | ||
tag, attrs.name.GetCString(), | ||
def_die ? llvm::utohexstr(def_die.GetID()) : "not found"); | ||
} | ||
|
||
if (def_die) { | ||
if (auto [it, inserted] = dwarf->GetDIEToType().try_emplace( | ||
def_die.GetDIE(), DIE_IS_BEING_PARSED); | ||
!inserted) { | ||
if (it->getSecond() == nullptr || | ||
it->getSecond() == DIE_IS_BEING_PARSED) | ||
return nullptr; | ||
return it->getSecond()->shared_from_this(); | ||
} | ||
attrs = ParsedDWARFTypeAttributes(def_die); | ||
} | ||
} | ||
|
||
if (!def_die) | ||
def_die = die; | ||
|
||
if (attrs.name) { | ||
GetUniqueTypeNameAndDeclaration(die, cu_language, unique_typename, | ||
GetUniqueTypeNameAndDeclaration(def_die, cu_language, unique_typename, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find the name def_die misleading here. IIUC, it may be a def die if the block above was run and successful? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1, for non-objc/objc++ cases, the parameter die could be a def die or decl die. Maybe move def_die into the above block and update the parameter die to def_die if def_die is valid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only catch there is that then |
||
unique_decl); | ||
if (log) { | ||
dwarf->GetObjectFile()->GetModule()->LogMessage( | ||
log, "SymbolFileDWARF({0:p}) - {1:x16}: {2} has unique name: {3} ", | ||
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag), | ||
static_cast<void *>(this), def_die.GetID(), DW_TAG_value_to_name(tag), | ||
unique_typename.AsCString()); | ||
} | ||
if (UniqueDWARFASTType *unique_ast_entry_type = | ||
dwarf->GetUniqueDWARFASTTypeMap().Find( | ||
unique_typename, die, unique_decl, byte_size, | ||
unique_typename, def_die, unique_decl, byte_size, | ||
attrs.is_forward_declaration)) { | ||
if (TypeSP type_sp = unique_ast_entry_type->m_type_sp) { | ||
dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); | ||
dwarf->GetDIEToType()[def_die.GetDIE()] = type_sp.get(); | ||
LinkDeclContextToDIE( | ||
GetCachedClangDeclContextForDIE(unique_ast_entry_type->m_die), die); | ||
GetCachedClangDeclContextForDIE(unique_ast_entry_type->m_die), | ||
def_die); | ||
// If the DIE being parsed in this function is a definition and the | ||
// entry in the map is a declaration, then we need to update the entry | ||
// to point to the definition DIE. | ||
if (!attrs.is_forward_declaration && | ||
unique_ast_entry_type->m_is_forward_declaration) { | ||
unique_ast_entry_type->UpdateToDefDIE(die, unique_decl, byte_size); | ||
unique_ast_entry_type->UpdateToDefDIE(def_die, unique_decl, | ||
byte_size); | ||
clang_type = type_sp->GetForwardCompilerType(); | ||
|
||
CompilerType compiler_type_no_qualifiers = | ||
ClangUtil::RemoveFastQualifiers(clang_type); | ||
dwarf->GetForwardDeclCompilerTypeToDIE().insert_or_assign( | ||
compiler_type_no_qualifiers.GetOpaqueQualType(), | ||
*die.GetDIERef()); | ||
*def_die.GetDIERef()); | ||
} | ||
return type_sp; | ||
} | ||
} | ||
} | ||
|
||
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), | ||
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", def_die.GetID(), | ||
DW_TAG_value_to_name(tag), type_name_cstr); | ||
|
||
int tag_decl_kind = -1; | ||
|
@@ -1726,22 +1767,22 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
if ((attrs.class_language == eLanguageTypeObjC || | ||
attrs.class_language == eLanguageTypeObjC_plus_plus) && | ||
!attrs.is_complete_objc_class && | ||
die.Supports_DW_AT_APPLE_objc_complete_type()) { | ||
def_die.Supports_DW_AT_APPLE_objc_complete_type()) { | ||
// We have a valid eSymbolTypeObjCClass class symbol whose name | ||
// matches the current objective C class that we are trying to find | ||
// and this DIE isn't the complete definition (we checked | ||
// is_complete_objc_class above and know it is false), so the real | ||
// definition is in here somewhere | ||
TypeSP type_sp = | ||
dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true); | ||
dwarf->FindCompleteObjCDefinitionTypeForDIE(def_die, attrs.name, true); | ||
|
||
if (!type_sp) { | ||
SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); | ||
if (debug_map_symfile) { | ||
// We weren't able to find a full declaration in this DWARF, | ||
// see if we have a declaration anywhere else... | ||
type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE( | ||
die, attrs.name, true); | ||
def_die, attrs.name, true); | ||
} | ||
} | ||
|
||
|
@@ -1751,8 +1792,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
log, | ||
"SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is an " | ||
"incomplete objc type, complete type is {5:x8}", | ||
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag), | ||
tag, attrs.name.GetCString(), type_sp->GetID()); | ||
static_cast<void *>(this), def_die.GetID(), | ||
DW_TAG_value_to_name(tag), tag, attrs.name.GetCString(), | ||
type_sp->GetID()); | ||
} | ||
return type_sp; | ||
} | ||
|
@@ -1761,18 +1803,18 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
if (attrs.is_forward_declaration) { | ||
// See if the type comes from a Clang module and if so, track down | ||
// that type. | ||
TypeSP type_sp = ParseTypeFromClangModule(sc, die, log); | ||
TypeSP type_sp = ParseTypeFromClangModule(sc, def_die, log); | ||
if (type_sp) | ||
return type_sp; | ||
} | ||
|
||
assert(tag_decl_kind != -1); | ||
UNUSED_IF_ASSERT_DISABLED(tag_decl_kind); | ||
clang::DeclContext *containing_decl_ctx = | ||
GetClangDeclContextContainingDIE(die, nullptr); | ||
GetClangDeclContextContainingDIE(def_die, nullptr); | ||
|
||
PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), | ||
containing_decl_ctx, die, | ||
containing_decl_ctx, def_die, | ||
attrs.name.GetCString()); | ||
|
||
if (attrs.accessibility == eAccessNone && containing_decl_ctx) { | ||
|
@@ -1785,31 +1827,32 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
} | ||
|
||
ClangASTMetadata metadata; | ||
metadata.SetUserID(die.GetID()); | ||
metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); | ||
metadata.SetUserID(def_die.GetID()); | ||
metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(def_die)); | ||
|
||
TypeSystemClang::TemplateParameterInfos template_param_infos; | ||
if (ParseTemplateParameterInfos(die, template_param_infos)) { | ||
if (ParseTemplateParameterInfos(def_die, template_param_infos)) { | ||
clang::ClassTemplateDecl *class_template_decl = | ||
m_ast.ParseClassTemplateDecl( | ||
containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility, | ||
attrs.name.GetCString(), tag_decl_kind, template_param_infos); | ||
containing_decl_ctx, GetOwningClangModule(def_die), | ||
attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, | ||
template_param_infos); | ||
if (!class_template_decl) { | ||
if (log) { | ||
dwarf->GetObjectFile()->GetModule()->LogMessage( | ||
log, | ||
"SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" " | ||
"clang::ClassTemplateDecl failed to return a decl.", | ||
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag), | ||
tag, attrs.name.GetCString()); | ||
static_cast<void *>(this), def_die.GetID(), | ||
DW_TAG_value_to_name(tag), tag, attrs.name.GetCString()); | ||
} | ||
return TypeSP(); | ||
} | ||
|
||
clang::ClassTemplateSpecializationDecl *class_specialization_decl = | ||
m_ast.CreateClassTemplateSpecializationDecl( | ||
containing_decl_ctx, GetOwningClangModule(die), class_template_decl, | ||
tag_decl_kind, template_param_infos); | ||
containing_decl_ctx, GetOwningClangModule(def_die), | ||
class_template_decl, tag_decl_kind, template_param_infos); | ||
clang_type = | ||
m_ast.CreateClassTemplateSpecializationType(class_specialization_decl); | ||
|
||
|
@@ -1819,13 +1862,13 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
|
||
if (!clang_type) { | ||
clang_type = m_ast.CreateRecordType( | ||
containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility, | ||
containing_decl_ctx, GetOwningClangModule(def_die), attrs.accessibility, | ||
attrs.name.GetCString(), tag_decl_kind, attrs.class_language, metadata, | ||
attrs.exports_symbols); | ||
} | ||
|
||
TypeSP type_sp = dwarf->MakeType( | ||
die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, | ||
def_die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, | ||
Type::eEncodingIsUID, &attrs.decl, clang_type, | ||
Type::ResolveState::Forward, | ||
TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class)); | ||
|
@@ -1835,7 +1878,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
// function prototypes. | ||
clang::DeclContext *type_decl_ctx = | ||
TypeSystemClang::GetDeclContextForType(clang_type); | ||
LinkDeclContextToDIE(type_decl_ctx, die); | ||
LinkDeclContextToDIE(type_decl_ctx, def_die); | ||
|
||
// UniqueDWARFASTType is large, so don't create a local variables on the | ||
// stack, put it on the heap. This function is often called recursively and | ||
|
@@ -1846,7 +1889,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
// copies of the same type over and over in the ASTContext for our | ||
// module | ||
unique_ast_entry_up->m_type_sp = type_sp; | ||
unique_ast_entry_up->m_die = die; | ||
unique_ast_entry_up->m_die = def_die; | ||
unique_ast_entry_up->m_declaration = unique_decl; | ||
unique_ast_entry_up->m_byte_size = byte_size; | ||
unique_ast_entry_up->m_is_forward_declaration = attrs.is_forward_declaration; | ||
|
@@ -1862,7 +1905,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, | |
dwarf->GetForwardDeclCompilerTypeToDIE() | ||
.try_emplace( | ||
ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(), | ||
*die.GetDIERef()) | ||
*def_die.GetDIERef()) | ||
.second; | ||
assert(inserted && "Type already in the forward declaration map!"); | ||
(void)inserted; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# REQUIRES: system-darwin | ||
|
||
# Test that we can set a breakpoint in a method of a class extension. | ||
# This requires us to parse the method into an AST type, and the context | ||
# too (which in DWARF is just a forward declaration). | ||
# | ||
# RUN: split-file %s %t | ||
# RUN: %clangxx_host %t/lib.m -c -g -gmodules -fmodules -o %t/lib.o | ||
# RUN: %clangxx_host %t/main.m -g -gmodules -fmodules %t/lib.o -o %t/a.out -framework Foundation | ||
# | ||
# RUN: %lldb %t/a.out -o "breakpoint set -f lib.m -l 6" -o exit | FileCheck %s | ||
|
||
# CHECK: (lldb) breakpoint set -f lib.m -l 6 | ||
# CHECK: Breakpoint 1: where = a.out`-[NSObject(Foo) func] | ||
|
||
#--- main.m | ||
int main() { | ||
return 0; | ||
} | ||
|
||
#--- lib.m | ||
#import <Foundation/Foundation.h> | ||
|
||
@implementation NSObject (Foo) | ||
- (NSError *)func { | ||
NSLog(@"Hello, World!"); | ||
return 0; | ||
} | ||
@end | ||
|
||
NSObject * func() { | ||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pretty much copied from
ParseEnum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'd also need to check for
eLanguageTypeObjCPlusPlus
here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would also be helpful to add a comment explaining why this block exists.