Skip to content
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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 73 additions & 30 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Copy link
Member Author

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

Copy link
Collaborator

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.

Copy link
Collaborator

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.

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,
Copy link
Collaborator

Choose a reason for hiding this comment

The 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?

Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only catch there is that then die needs to be a value parameter, but I think that's a fine tradeoff. I contemplated doing that in #96484 (which is where the def_die name comes from, I think), and I didn't do it only because knew (well, I thought I knew) that code was going to be temporary).

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;
Expand All @@ -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);
}
}

Expand All @@ -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;
}
Expand All @@ -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) {
Expand All @@ -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);

Expand All @@ -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));
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand Down
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;
}
Loading