Skip to content

Commit 5a16645

Browse files
authored
Reland "[lldb][DWARF] Remove object_pointer from ParsedDWARFAttributes (#145065)" (#145126)
This reverts commit 8775119. This fixes the `TestObjCInBlockVars.py` LLDB API test. The issue was that `GetCXXObjectParameter` wouldn't deduce the object parameter of Objective-C method definitions correctly. In DWARF those don't have a `DW_AT_specification` (so no link back to a DeclContext that is a class type). The fix is to only check the validity of the DeclContext DIE *if* no `DW_AT_object_pointer` exists on the DIE. If `DW_AT_object_pointer` does exist, we should just always use that as the object_parameter.
1 parent 634fe0d commit 5a16645

File tree

3 files changed

+176
-28
lines changed

3 files changed

+176
-28
lines changed

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

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -167,16 +167,17 @@ DWARFASTParserClang::GetObjectParameter(const DWARFDIE &subprogram,
167167
subprogram.Tag() == DW_TAG_inlined_subroutine ||
168168
subprogram.Tag() == DW_TAG_subroutine_type);
169169

170-
if (!decl_ctx_die.IsStructUnionOrClass())
171-
return {};
172-
173170
if (DWARFDIE object_parameter =
174171
subprogram.GetAttributeValueAsReferenceDIE(DW_AT_object_pointer))
175172
return object_parameter;
176173

177174
// If no DW_AT_object_pointer was specified, assume the implicit object
178175
// parameter is the first parameter to the function, is called "this" and is
179176
// artificial (which is what most compilers would generate).
177+
178+
if (!decl_ctx_die.IsStructUnionOrClass())
179+
return {};
180+
180181
auto children = subprogram.children();
181182
auto it = llvm::find_if(children, [](const DWARFDIE &child) {
182183
return child.Tag() == DW_TAG_formal_parameter;
@@ -441,15 +442,6 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
441442
name.SetCString(form_value.AsCString());
442443
break;
443444

444-
case DW_AT_object_pointer:
445-
// GetAttributes follows DW_AT_specification.
446-
// DW_TAG_subprogram definitions and declarations may both
447-
// have a DW_AT_object_pointer. Don't overwrite the one
448-
// we parsed for the definition with the one from the declaration.
449-
if (!object_pointer.IsValid())
450-
object_pointer = form_value.Reference();
451-
break;
452-
453445
case DW_AT_signature:
454446
signature = form_value;
455447
break;
@@ -1112,7 +1104,7 @@ bool DWARFASTParserClang::ParseObjCMethod(
11121104
std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
11131105
const DWARFDIE &die, CompilerType clang_type,
11141106
const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die,
1115-
bool is_static, bool &ignore_containing_context) {
1107+
const DWARFDIE &object_parameter, bool &ignore_containing_context) {
11161108
Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups);
11171109
SymbolFileDWARF *dwarf = die.GetDWARF();
11181110
assert(dwarf);
@@ -1196,6 +1188,9 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
11961188
TypeSystemClang::GetDeclContextForType(class_opaque_type), die,
11971189
attrs.name.GetCString());
11981190

1191+
// In DWARF, a C++ method is static if it has no object parameter child.
1192+
const bool is_static = !object_parameter.IsValid();
1193+
11991194
// We have a C++ member function with no children (this pointer!) and clang
12001195
// will get mad if we try and make a function that isn't well formed in the
12011196
// DWARF, so we will just skip it...
@@ -1221,9 +1216,7 @@ std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod(
12211216
ClangASTMetadata metadata;
12221217
metadata.SetUserID(die.GetID());
12231218

1224-
char const *object_pointer_name =
1225-
attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
1226-
if (object_pointer_name) {
1219+
if (char const *object_pointer_name = object_parameter.GetName()) {
12271220
metadata.SetObjectPtrName(object_pointer_name);
12281221
LLDB_LOGF(log, "Setting object pointer name: %s on method object %p.\n",
12291222
object_pointer_name, static_cast<void *>(cxx_method_decl));
@@ -1319,11 +1312,9 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
13191312
type_handled =
13201313
ParseObjCMethod(*objc_method, die, clang_type, attrs, is_variadic);
13211314
} else if (is_cxx_method) {
1322-
// In DWARF, a C++ method is static if it has no object parameter child.
1323-
const bool is_static = !object_parameter.IsValid();
13241315
auto [handled, type_sp] =
1325-
ParseCXXMethod(die, clang_type, attrs, decl_ctx_die, is_static,
1326-
ignore_containing_context);
1316+
ParseCXXMethod(die, clang_type, attrs, decl_ctx_die,
1317+
object_parameter, ignore_containing_context);
13271318
if (type_sp)
13281319
return type_sp;
13291320

@@ -1418,9 +1409,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
14181409
ClangASTMetadata metadata;
14191410
metadata.SetUserID(die.GetID());
14201411

1421-
char const *object_pointer_name =
1422-
attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr;
1423-
if (object_pointer_name) {
1412+
if (char const *object_pointer_name = object_parameter.GetName()) {
14241413
metadata.SetObjectPtrName(object_pointer_name);
14251414
LLDB_LOGF(log,
14261415
"Setting object pointer name: %s on function "

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,8 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
480480
/// \param[in] decl_ctx_die The DIE representing the DeclContext of the C++
481481
/// method being parsed.
482482
///
483-
/// \param[in] is_static Is true iff we're parsing a static method.
483+
/// \param[in] object_parameter The DIE of this subprogram's object parameter.
484+
/// May be an invalid DIE for C++ static methods.
484485
///
485486
/// \param[out] ignore_containing_context Will get set to true if the caller
486487
/// should treat this C++ method as-if it was not a C++ method.
@@ -495,7 +496,8 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
495496
lldb_private::CompilerType clang_type,
496497
const ParsedDWARFTypeAttributes &attrs,
497498
const lldb_private::plugin::dwarf::DWARFDIE &decl_ctx_die,
498-
bool is_static, bool &ignore_containing_context);
499+
const lldb_private::plugin::dwarf::DWARFDIE &object_parameter,
500+
bool &ignore_containing_context);
499501

500502
lldb::TypeSP ParseArrayType(const lldb_private::plugin::dwarf::DWARFDIE &die,
501503
const ParsedDWARFTypeAttributes &attrs);
@@ -565,7 +567,6 @@ struct ParsedDWARFTypeAttributes {
565567
const char *mangled_name = nullptr;
566568
lldb_private::ConstString name;
567569
lldb_private::Declaration decl;
568-
lldb_private::plugin::dwarf::DWARFDIE object_pointer;
569570
lldb_private::plugin::dwarf::DWARFFormValue abstract_origin;
570571
lldb_private::plugin::dwarf::DWARFFormValue containing_type;
571572
lldb_private::plugin::dwarf::DWARFFormValue signature;

lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp

Lines changed: 160 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,8 +742,8 @@ TEST_F(DWARFASTParserClangTests, TestUniqueDWARFASTTypeMap_CppInsertMapFind) {
742742
ASSERT_EQ(type_sp, reparsed_type_sp);
743743
}
744744

745-
TEST_F(DWARFASTParserClangTests, TestParseDWARFAttributes_ObjectPointer) {
746-
// This tests the behaviour of ParsedDWARFTypeAttributes
745+
TEST_F(DWARFASTParserClangTests, TestObjectPointer) {
746+
// This tests the behaviour of DWARFASTParserClang
747747
// for DW_TAG_subprogram definitions which have a DW_AT_object_pointer
748748
// *and* a DW_AT_specification that also has a DW_AT_object_pointer.
749749
// We don't want the declaration DW_AT_object_pointer to overwrite the
@@ -916,6 +916,164 @@ TEST_F(DWARFASTParserClangTests, TestParseDWARFAttributes_ObjectPointer) {
916916
}
917917
}
918918

919+
TEST_F(DWARFASTParserClangTests,
920+
TestObjectPointer_NoSpecificationOnDefinition) {
921+
// This tests the behaviour of DWARFASTParserClang
922+
// for DW_TAG_subprogram definitions which have a DW_AT_object_pointer
923+
// but no DW_AT_specification that would link back to its declaration.
924+
// This is how Objective-C class method definitions are emitted.
925+
926+
const char *yamldata = R"(
927+
--- !ELF
928+
FileHeader:
929+
Class: ELFCLASS64
930+
Data: ELFDATA2LSB
931+
Type: ET_EXEC
932+
Machine: EM_AARCH64
933+
DWARF:
934+
debug_str:
935+
- Context
936+
- func
937+
- this
938+
debug_abbrev:
939+
- ID: 0
940+
Table:
941+
- Code: 0x1
942+
Tag: DW_TAG_compile_unit
943+
Children: DW_CHILDREN_yes
944+
Attributes:
945+
- Attribute: DW_AT_language
946+
Form: DW_FORM_data2
947+
- Code: 0x2
948+
Tag: DW_TAG_structure_type
949+
Children: DW_CHILDREN_yes
950+
Attributes:
951+
- Attribute: DW_AT_name
952+
Form: DW_FORM_strp
953+
- Code: 0x3
954+
Tag: DW_TAG_subprogram
955+
Children: DW_CHILDREN_yes
956+
Attributes:
957+
- Attribute: DW_AT_name
958+
Form: DW_FORM_strp
959+
- Attribute: DW_AT_declaration
960+
Form: DW_FORM_flag_present
961+
- Attribute: DW_AT_object_pointer
962+
Form: DW_FORM_ref4
963+
- Attribute: DW_AT_artificial
964+
Form: DW_FORM_flag_present
965+
- Attribute: DW_AT_external
966+
Form: DW_FORM_flag_present
967+
- Code: 0x4
968+
Tag: DW_TAG_formal_parameter
969+
Children: DW_CHILDREN_no
970+
Attributes:
971+
- Attribute: DW_AT_artificial
972+
Form: DW_FORM_flag_present
973+
- Code: 0x5
974+
Tag: DW_TAG_subprogram
975+
Children: DW_CHILDREN_yes
976+
Attributes:
977+
- Attribute: DW_AT_object_pointer
978+
Form: DW_FORM_ref4
979+
- Code: 0x6
980+
Tag: DW_TAG_formal_parameter
981+
Children: DW_CHILDREN_no
982+
Attributes:
983+
- Attribute: DW_AT_name
984+
Form: DW_FORM_strp
985+
- Attribute: DW_AT_artificial
986+
Form: DW_FORM_flag_present
987+
debug_info:
988+
- Version: 5
989+
UnitType: DW_UT_compile
990+
AddrSize: 8
991+
Entries:
992+
993+
# DW_TAG_compile_unit
994+
# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
995+
996+
- AbbrCode: 0x1
997+
Values:
998+
- Value: 0x04
999+
1000+
# DW_TAG_structure_type
1001+
# DW_AT_name [DW_FORM_strp] ("Context")
1002+
1003+
- AbbrCode: 0x2
1004+
Values:
1005+
- Value: 0x0
1006+
1007+
# DW_TAG_subprogram
1008+
# DW_AT_name [DW_FORM_strp] ("func")
1009+
# DW_AT_object_pointer [DW_FORM_ref4]
1010+
- AbbrCode: 0x3
1011+
Values:
1012+
- Value: 0x8
1013+
- Value: 0x1
1014+
- Value: 0x1d
1015+
- Value: 0x1
1016+
- Value: 0x1
1017+
1018+
# DW_TAG_formal_parameter
1019+
# DW_AT_artificial
1020+
- AbbrCode: 0x4
1021+
Values:
1022+
- Value: 0x1
1023+
1024+
- AbbrCode: 0x0
1025+
- AbbrCode: 0x0
1026+
1027+
# DW_TAG_subprogram
1028+
# DW_AT_object_pointer [DW_FORM_ref4] ("this")
1029+
- AbbrCode: 0x5
1030+
Values:
1031+
- Value: 0x25
1032+
1033+
# DW_TAG_formal_parameter
1034+
# DW_AT_name [DW_FORM_strp] ("this")
1035+
# DW_AT_artificial
1036+
- AbbrCode: 0x6
1037+
Values:
1038+
- Value: 0xd
1039+
- Value: 0x1
1040+
1041+
- AbbrCode: 0x0
1042+
- AbbrCode: 0x0
1043+
...
1044+
)";
1045+
YAMLModuleTester t(yamldata);
1046+
1047+
DWARFUnit *unit = t.GetDwarfUnit();
1048+
ASSERT_NE(unit, nullptr);
1049+
const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
1050+
ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
1051+
ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
1052+
DWARFDIE cu_die(unit, cu_entry);
1053+
1054+
auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast");
1055+
auto &ast_ctx = *holder->GetAST();
1056+
DWARFASTParserClangStub ast_parser(ast_ctx);
1057+
1058+
auto context_die = cu_die.GetFirstChild();
1059+
ASSERT_TRUE(context_die.IsValid());
1060+
ASSERT_EQ(context_die.Tag(), DW_TAG_structure_type);
1061+
1062+
auto subprogram_definition = context_die.GetSibling();
1063+
ASSERT_TRUE(subprogram_definition.IsValid());
1064+
ASSERT_EQ(subprogram_definition.Tag(), DW_TAG_subprogram);
1065+
ASSERT_FALSE(subprogram_definition.GetAttributeValueAsOptionalUnsigned(
1066+
DW_AT_external));
1067+
ASSERT_FALSE(
1068+
subprogram_definition.GetAttributeValueAsReferenceDIE(DW_AT_specification)
1069+
.IsValid());
1070+
1071+
auto param_die = subprogram_definition.GetFirstChild();
1072+
ASSERT_TRUE(param_die.IsValid());
1073+
EXPECT_EQ(param_die,
1074+
ast_parser.GetObjectParameter(subprogram_definition, {}));
1075+
}
1076+
9191077
TEST_F(DWARFASTParserClangTests, TestParseSubroutine_ExplicitObjectParameter) {
9201078
// Tests parsing of a C++ non-static member function with an explicit object
9211079
// parameter that isn't called "this" and is not a pointer (but a CV-qualified

0 commit comments

Comments
 (0)