Skip to content

Commit 4b1eb84

Browse files
committed
[WIP][lldb][DWARFASTParserClang] Eagerly search definitions for Objective-C classes
This patch essentially reverts the definition DIE delay changes (in https://github.com/llvm/llvm-project/pull/98361/files) for Objective-C. The problem we've been seeing is as follows: 1. An Objetive-C class extension is represented in DWARF as: ``` DW_TAG_structure_type DW_AT_declaration (true) DW_AT_name ("ExtendedClass") DW_TAG_subprogram DW_AT_name ("extensionMethod") ... ``` I.e., it is a forward declaration of the extended class, but that forward declaration has children methods. 2. When we set a breakpoint in one of those methods we parse the subprogram DIE and try to create an `ObjCMethodDecl` for it (and attach it to the context). 3. When parsing the subprogram DIE, we first try to complete the DeclContext. Because `ExtendedClass` is only a forward declaration and we don't try to fetch the definition DIE eagerly anymore, LLDB has no idea that we're dealing with an Objective-C type. So it goes ahead and constructs it as a `CXXRecordDecl`. This confuses `DWARFASTParserClang::ParseObjCMethod` because it expects the context to be an `clang::ObjCObjectOrInterfaceType`. So it bails and we end up crashing because we try to attach a `FunctionDecl` to an incomplete `CXXRecordDecl` (which wasn't even forcefully completed). Since there's no good way to tell whether a forward declaration is an Objective-C type, the only solution I can really see here is to eagerly fetch the definition for Objective-C types.
1 parent 9472c5f commit 4b1eb84

File tree

2 files changed

+106
-30
lines changed

2 files changed

+106
-30
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

+73-30
Original file line numberDiff line numberDiff line change
@@ -1671,43 +1671,84 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
16711671
attrs.is_forward_declaration = true;
16721672
}
16731673

1674+
DWARFDIE def_die;
1675+
if (attrs.is_forward_declaration && cu_language == eLanguageTypeObjC) {
1676+
def_die = dwarf->FindDefinitionDIE(die);
1677+
1678+
if (!def_die) {
1679+
SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile();
1680+
if (debug_map_symfile) {
1681+
// We weren't able to find a full declaration in this DWARF,
1682+
// see if we have a declaration anywhere else...
1683+
def_die = debug_map_symfile->FindDefinitionDIE(die);
1684+
}
1685+
}
1686+
1687+
if (log) {
1688+
dwarf->GetObjectFile()->GetModule()->LogMessage(
1689+
log,
1690+
"SymbolFileDWARF({0:p}) - {1:x16}}: {2} ({3}) type \"{4}\" is a "
1691+
"forward declaration, complete DIE is {5}",
1692+
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag),
1693+
tag, attrs.name.GetCString(),
1694+
def_die ? llvm::utohexstr(def_die.GetID()) : "not found");
1695+
}
1696+
1697+
if (def_die) {
1698+
if (auto [it, inserted] = dwarf->GetDIEToType().try_emplace(
1699+
def_die.GetDIE(), DIE_IS_BEING_PARSED);
1700+
!inserted) {
1701+
if (it->getSecond() == nullptr ||
1702+
it->getSecond() == DIE_IS_BEING_PARSED)
1703+
return nullptr;
1704+
return it->getSecond()->shared_from_this();
1705+
}
1706+
attrs = ParsedDWARFTypeAttributes(def_die);
1707+
}
1708+
}
1709+
1710+
if (!def_die)
1711+
def_die = die;
1712+
16741713
if (attrs.name) {
1675-
GetUniqueTypeNameAndDeclaration(die, cu_language, unique_typename,
1714+
GetUniqueTypeNameAndDeclaration(def_die, cu_language, unique_typename,
16761715
unique_decl);
16771716
if (log) {
16781717
dwarf->GetObjectFile()->GetModule()->LogMessage(
16791718
log, "SymbolFileDWARF({0:p}) - {1:x16}: {2} has unique name: {3} ",
1680-
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag),
1719+
static_cast<void *>(this), def_die.GetID(), DW_TAG_value_to_name(tag),
16811720
unique_typename.AsCString());
16821721
}
16831722
if (UniqueDWARFASTType *unique_ast_entry_type =
16841723
dwarf->GetUniqueDWARFASTTypeMap().Find(
1685-
unique_typename, die, unique_decl, byte_size,
1724+
unique_typename, def_die, unique_decl, byte_size,
16861725
attrs.is_forward_declaration)) {
16871726
if (TypeSP type_sp = unique_ast_entry_type->m_type_sp) {
1688-
dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get();
1727+
dwarf->GetDIEToType()[def_die.GetDIE()] = type_sp.get();
16891728
LinkDeclContextToDIE(
1690-
GetCachedClangDeclContextForDIE(unique_ast_entry_type->m_die), die);
1729+
GetCachedClangDeclContextForDIE(unique_ast_entry_type->m_die),
1730+
def_die);
16911731
// If the DIE being parsed in this function is a definition and the
16921732
// entry in the map is a declaration, then we need to update the entry
16931733
// to point to the definition DIE.
16941734
if (!attrs.is_forward_declaration &&
16951735
unique_ast_entry_type->m_is_forward_declaration) {
1696-
unique_ast_entry_type->UpdateToDefDIE(die, unique_decl, byte_size);
1736+
unique_ast_entry_type->UpdateToDefDIE(def_die, unique_decl,
1737+
byte_size);
16971738
clang_type = type_sp->GetForwardCompilerType();
16981739

16991740
CompilerType compiler_type_no_qualifiers =
17001741
ClangUtil::RemoveFastQualifiers(clang_type);
17011742
dwarf->GetForwardDeclCompilerTypeToDIE().insert_or_assign(
17021743
compiler_type_no_qualifiers.GetOpaqueQualType(),
1703-
*die.GetDIERef());
1744+
*def_die.GetDIERef());
17041745
}
17051746
return type_sp;
17061747
}
17071748
}
17081749
}
17091750

1710-
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
1751+
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", def_die.GetID(),
17111752
DW_TAG_value_to_name(tag), type_name_cstr);
17121753

17131754
int tag_decl_kind = -1;
@@ -1726,22 +1767,22 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
17261767
if ((attrs.class_language == eLanguageTypeObjC ||
17271768
attrs.class_language == eLanguageTypeObjC_plus_plus) &&
17281769
!attrs.is_complete_objc_class &&
1729-
die.Supports_DW_AT_APPLE_objc_complete_type()) {
1770+
def_die.Supports_DW_AT_APPLE_objc_complete_type()) {
17301771
// We have a valid eSymbolTypeObjCClass class symbol whose name
17311772
// matches the current objective C class that we are trying to find
17321773
// and this DIE isn't the complete definition (we checked
17331774
// is_complete_objc_class above and know it is false), so the real
17341775
// definition is in here somewhere
17351776
TypeSP type_sp =
1736-
dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true);
1777+
dwarf->FindCompleteObjCDefinitionTypeForDIE(def_die, attrs.name, true);
17371778

17381779
if (!type_sp) {
17391780
SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile();
17401781
if (debug_map_symfile) {
17411782
// We weren't able to find a full declaration in this DWARF,
17421783
// see if we have a declaration anywhere else...
17431784
type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE(
1744-
die, attrs.name, true);
1785+
def_die, attrs.name, true);
17451786
}
17461787
}
17471788

@@ -1751,8 +1792,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
17511792
log,
17521793
"SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is an "
17531794
"incomplete objc type, complete type is {5:x8}",
1754-
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag),
1755-
tag, attrs.name.GetCString(), type_sp->GetID());
1795+
static_cast<void *>(this), def_die.GetID(),
1796+
DW_TAG_value_to_name(tag), tag, attrs.name.GetCString(),
1797+
type_sp->GetID());
17561798
}
17571799
return type_sp;
17581800
}
@@ -1761,18 +1803,18 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
17611803
if (attrs.is_forward_declaration) {
17621804
// See if the type comes from a Clang module and if so, track down
17631805
// that type.
1764-
TypeSP type_sp = ParseTypeFromClangModule(sc, die, log);
1806+
TypeSP type_sp = ParseTypeFromClangModule(sc, def_die, log);
17651807
if (type_sp)
17661808
return type_sp;
17671809
}
17681810

17691811
assert(tag_decl_kind != -1);
17701812
UNUSED_IF_ASSERT_DISABLED(tag_decl_kind);
17711813
clang::DeclContext *containing_decl_ctx =
1772-
GetClangDeclContextContainingDIE(die, nullptr);
1814+
GetClangDeclContextContainingDIE(def_die, nullptr);
17731815

17741816
PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(),
1775-
containing_decl_ctx, die,
1817+
containing_decl_ctx, def_die,
17761818
attrs.name.GetCString());
17771819

17781820
if (attrs.accessibility == eAccessNone && containing_decl_ctx) {
@@ -1785,31 +1827,32 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
17851827
}
17861828

17871829
ClangASTMetadata metadata;
1788-
metadata.SetUserID(die.GetID());
1789-
metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die));
1830+
metadata.SetUserID(def_die.GetID());
1831+
metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(def_die));
17901832

17911833
TypeSystemClang::TemplateParameterInfos template_param_infos;
1792-
if (ParseTemplateParameterInfos(die, template_param_infos)) {
1834+
if (ParseTemplateParameterInfos(def_die, template_param_infos)) {
17931835
clang::ClassTemplateDecl *class_template_decl =
17941836
m_ast.ParseClassTemplateDecl(
1795-
containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility,
1796-
attrs.name.GetCString(), tag_decl_kind, template_param_infos);
1837+
containing_decl_ctx, GetOwningClangModule(def_die),
1838+
attrs.accessibility, attrs.name.GetCString(), tag_decl_kind,
1839+
template_param_infos);
17971840
if (!class_template_decl) {
17981841
if (log) {
17991842
dwarf->GetObjectFile()->GetModule()->LogMessage(
18001843
log,
18011844
"SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" "
18021845
"clang::ClassTemplateDecl failed to return a decl.",
1803-
static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag),
1804-
tag, attrs.name.GetCString());
1846+
static_cast<void *>(this), def_die.GetID(),
1847+
DW_TAG_value_to_name(tag), tag, attrs.name.GetCString());
18051848
}
18061849
return TypeSP();
18071850
}
18081851

18091852
clang::ClassTemplateSpecializationDecl *class_specialization_decl =
18101853
m_ast.CreateClassTemplateSpecializationDecl(
1811-
containing_decl_ctx, GetOwningClangModule(die), class_template_decl,
1812-
tag_decl_kind, template_param_infos);
1854+
containing_decl_ctx, GetOwningClangModule(def_die),
1855+
class_template_decl, tag_decl_kind, template_param_infos);
18131856
clang_type =
18141857
m_ast.CreateClassTemplateSpecializationType(class_specialization_decl);
18151858

@@ -1819,13 +1862,13 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
18191862

18201863
if (!clang_type) {
18211864
clang_type = m_ast.CreateRecordType(
1822-
containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility,
1865+
containing_decl_ctx, GetOwningClangModule(def_die), attrs.accessibility,
18231866
attrs.name.GetCString(), tag_decl_kind, attrs.class_language, metadata,
18241867
attrs.exports_symbols);
18251868
}
18261869

18271870
TypeSP type_sp = dwarf->MakeType(
1828-
die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID,
1871+
def_die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID,
18291872
Type::eEncodingIsUID, &attrs.decl, clang_type,
18301873
Type::ResolveState::Forward,
18311874
TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class));
@@ -1835,7 +1878,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
18351878
// function prototypes.
18361879
clang::DeclContext *type_decl_ctx =
18371880
TypeSystemClang::GetDeclContextForType(clang_type);
1838-
LinkDeclContextToDIE(type_decl_ctx, die);
1881+
LinkDeclContextToDIE(type_decl_ctx, def_die);
18391882

18401883
// UniqueDWARFASTType is large, so don't create a local variables on the
18411884
// stack, put it on the heap. This function is often called recursively and
@@ -1846,7 +1889,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
18461889
// copies of the same type over and over in the ASTContext for our
18471890
// module
18481891
unique_ast_entry_up->m_type_sp = type_sp;
1849-
unique_ast_entry_up->m_die = die;
1892+
unique_ast_entry_up->m_die = def_die;
18501893
unique_ast_entry_up->m_declaration = unique_decl;
18511894
unique_ast_entry_up->m_byte_size = byte_size;
18521895
unique_ast_entry_up->m_is_forward_declaration = attrs.is_forward_declaration;
@@ -1862,7 +1905,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc,
18621905
dwarf->GetForwardDeclCompilerTypeToDIE()
18631906
.try_emplace(
18641907
ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(),
1865-
*die.GetDIERef())
1908+
*def_die.GetDIERef())
18661909
.second;
18671910
assert(inserted && "Type already in the forward declaration map!");
18681911
(void)inserted;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# REQUIRES: system-darwin
2+
3+
# Test that we can set a breakpoint in a method of a class extension.
4+
# This requires us to parse the method into an AST type, and the context
5+
# too (which in DWARF is just a forward declaration).
6+
#
7+
# RUN: split-file %s %t
8+
# RUN: %clangxx_host %t/lib.m -c -g -gmodules -fmodules -o %t/lib.o
9+
# RUN: %clangxx_host %t/main.m -g -gmodules -fmodules %t/lib.o -o %t/a.out -framework Foundation
10+
#
11+
# RUN: %lldb %t/a.out -o "breakpoint set -f lib.m -l 6" -o exit | FileCheck %s
12+
13+
# CHECK: (lldb) breakpoint set -f lib.m -l 6
14+
# CHECK: Breakpoint 1: where = a.out`-[NSObject(Foo) func]
15+
16+
#--- main.m
17+
int main() {
18+
return 0;
19+
}
20+
21+
#--- lib.m
22+
#import <Foundation/Foundation.h>
23+
24+
@implementation NSObject (Foo)
25+
- (NSError *)func {
26+
NSLog(@"Hello, World!");
27+
return 0;
28+
}
29+
@end
30+
31+
NSObject * func() {
32+
return 0;
33+
}

0 commit comments

Comments
 (0)