Skip to content

Commit 22e8f64

Browse files
committed
[lldb][DWARFASTParserClang] Support constant index encoding of DW_AT_object_pointer
Starting with llvm#124790, Clang emits `DW_AT_object_pointer` encoded as integer constants rather than DIE references. This patch accounts for this.
1 parent 09e794c commit 22e8f64

File tree

3 files changed

+244
-20
lines changed

3 files changed

+244
-20
lines changed

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

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,46 @@ DWARFASTParserClang::GetCXXObjectParameter(const DWARFDIE &subprogram,
174174
if (!decl_ctx_die.IsStructUnionOrClass())
175175
return {};
176176

177-
if (DWARFDIE object_parameter =
178-
subprogram.GetAttributeValueAsReferenceDIE(DW_AT_object_pointer))
179-
return object_parameter;
177+
// The DW_AT_object_pointer may be either encoded as a reference to a DIE,
178+
// in which case that's the object parameter we want. Or it can be a constant
179+
// index of the parameter.
180+
std::optional<size_t> object_pointer_index;
181+
DWARFFormValue form_value;
182+
if (subprogram.GetDIE()->GetAttributeValue(
183+
subprogram.GetCU(), DW_AT_object_pointer, form_value,
184+
/*end_attr_offset_ptr=*/nullptr, /*check_elaborating_dies=*/true)) {
185+
if (auto ref = form_value.Reference())
186+
return ref;
187+
188+
object_pointer_index = form_value.Unsigned();
189+
}
190+
191+
// Try to find the DW_TAG_formal_parameter via object_pointer_index.
192+
DWARFDIE object_pointer;
193+
size_t param_index = 0;
194+
for (const auto &child : subprogram.children()) {
195+
if (child.Tag() != DW_TAG_formal_parameter)
196+
continue;
180197

181-
// If no DW_AT_object_pointer was specified, assume the implicit object
182-
// parameter is the first parameter to the function, is called "this" and is
183-
// artificial (which is what most compilers would generate).
184-
auto children = subprogram.children();
185-
auto it = llvm::find_if(children, [](const DWARFDIE &child) {
186-
return child.Tag() == DW_TAG_formal_parameter;
187-
});
198+
if (param_index == object_pointer_index.value_or(0))
199+
object_pointer = child;
200+
201+
++param_index;
202+
}
188203

189-
if (it == children.end())
204+
// No formal parameter found for object pointer index.
205+
// Nothing to be done.
206+
if (!object_pointer)
190207
return {};
191208

192-
DWARFDIE object_pointer = *it;
209+
// We found the object pointer encoded via DW_AT_object_pointer.
210+
// No need for the remaining heuristics.
211+
if (object_pointer_index)
212+
return object_pointer;
193213

214+
// If no DW_AT_object_pointer was specified, assume the implicit object
215+
// parameter is the first parameter to the function, is called "this" and is
216+
// artificial (which is what most compilers would generate).
194217
if (!object_pointer.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
195218
return {};
196219

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
// XFAIL: *
2+
//
3+
// FIXME: Explicit object parameter is not shown in
4+
// type lookup output. This is because we don't attach
5+
// valid source locations to decls in the DWARF AST,
6+
// so the ParmVarDecl::isExplicitObjectParameter fails.
27

38
// Tests that we correctly deduce the CV-quals and storage
49
// class of explicit object member functions.
@@ -8,15 +13,15 @@
813
//
914
// CHECK: (lldb) type lookup Foo
1015
// CHECK-NEXT: struct Foo {
11-
// CHECK-NEXT: void Method(Foo);
12-
// CHECK-NEXT: void cMethod(const Foo &) const;
13-
// CHECK-NEXT: void vMethod(volatile Foo &) volatile;
14-
// CHECK-NEXT: void cvMethod(const volatile Foo &) const volatile;
16+
// CHECK-NEXT: void Method(this Foo);
17+
// CHECK-NEXT: void cMethod(this const Foo &) const;
18+
// CHECK-NEXT: void vMethod(this volatile Foo &) volatile;
19+
// CHECK-NEXT: void cvMethod(this const volatile Foo &) const volatile;
1520
// CHECK-NEXT: }
1621

1722
struct Foo {
18-
void Method(this Foo) {}
19-
void cMethod(this Foo const &) {}
20-
void vMethod(this Foo volatile &) {}
21-
void cvMethod(this Foo const volatile &) {}
23+
[[gnu::always_inline]] void Method(this Foo) {}
24+
[[gnu::always_inline]] void cMethod(this Foo const &) {}
25+
[[gnu::always_inline]] void vMethod(this Foo volatile &) {}
26+
[[gnu::always_inline]] void cvMethod(this Foo const volatile &) {}
2227
} f;

lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,3 +1266,199 @@ TEST_F(DWARFASTParserClangTests, TestParseSubroutine_ParameterCreation) {
12661266
EXPECT_EQ(func->getParamDecl(1)->getDeclContext(), func);
12671267
EXPECT_EQ(func->getParamDecl(1)->getName(), "namedParam");
12681268
}
1269+
1270+
TEST_F(DWARFASTParserClangTests, TestParseDWARFAttributes_ObjectPointerIndex) {
1271+
// This tests the behaviour of ParsedDWARFTypeAttributes
1272+
// for DW_TAG_subprogram definitions which have a DW_AT_object_pointer
1273+
// that encodes a constant index (instead of a DIE reference).
1274+
1275+
const char *yamldata = R"(
1276+
--- !ELF
1277+
FileHeader:
1278+
Class: ELFCLASS64
1279+
Data: ELFDATA2LSB
1280+
Type: ET_EXEC
1281+
Machine: EM_AARCH64
1282+
DWARF:
1283+
debug_str:
1284+
- Context
1285+
- func
1286+
- this
1287+
- self
1288+
- arg
1289+
debug_abbrev:
1290+
- ID: 0
1291+
Table:
1292+
- Code: 0x1
1293+
Tag: DW_TAG_compile_unit
1294+
Children: DW_CHILDREN_yes
1295+
Attributes:
1296+
- Attribute: DW_AT_language
1297+
Form: DW_FORM_data2
1298+
- Code: 0x2
1299+
Tag: DW_TAG_structure_type
1300+
Children: DW_CHILDREN_yes
1301+
Attributes:
1302+
- Attribute: DW_AT_name
1303+
Form: DW_FORM_strp
1304+
- Code: 0x3
1305+
Tag: DW_TAG_subprogram
1306+
Children: DW_CHILDREN_yes
1307+
Attributes:
1308+
- Attribute: DW_AT_name
1309+
Form: DW_FORM_strp
1310+
- Attribute: DW_AT_declaration
1311+
Form: DW_FORM_flag_present
1312+
- Attribute: DW_AT_object_pointer
1313+
Form: DW_FORM_implicit_const
1314+
Value: 1
1315+
- Attribute: DW_AT_external
1316+
Form: DW_FORM_flag_present
1317+
- Code: 0x4
1318+
Tag: DW_TAG_subprogram
1319+
Children: DW_CHILDREN_yes
1320+
Attributes:
1321+
- Attribute: DW_AT_name
1322+
Form: DW_FORM_strp
1323+
- Attribute: DW_AT_declaration
1324+
Form: DW_FORM_flag_present
1325+
- Attribute: DW_AT_object_pointer
1326+
Form: DW_FORM_implicit_const
1327+
Value: 0
1328+
- Attribute: DW_AT_external
1329+
Form: DW_FORM_flag_present
1330+
1331+
- Code: 0x5
1332+
Tag: DW_TAG_formal_parameter
1333+
Children: DW_CHILDREN_no
1334+
Attributes:
1335+
- Attribute: DW_AT_name
1336+
Form: DW_FORM_strp
1337+
1338+
- Code: 0x6
1339+
Tag: DW_TAG_formal_parameter
1340+
Children: DW_CHILDREN_no
1341+
Attributes:
1342+
- Attribute: DW_AT_name
1343+
Form: DW_FORM_strp
1344+
- Attribute: DW_AT_artificial
1345+
Form: DW_FORM_flag_present
1346+
1347+
debug_info:
1348+
- Version: 5
1349+
UnitType: DW_UT_compile
1350+
AddrSize: 8
1351+
Entries:
1352+
1353+
# DW_TAG_compile_unit
1354+
# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
1355+
1356+
- AbbrCode: 0x1
1357+
Values:
1358+
- Value: 0x04
1359+
1360+
# DW_TAG_structure_type
1361+
# DW_AT_name [DW_FORM_strp] ("Context")
1362+
1363+
- AbbrCode: 0x2
1364+
Values:
1365+
- Value: 0x0
1366+
1367+
# DW_TAG_subprogram
1368+
# DW_AT_name [DW_FORM_strp] ("func")
1369+
# DW_AT_object_pointer [DW_FORM_implicit_const] (1)
1370+
- AbbrCode: 0x3
1371+
Values:
1372+
- Value: 0x8
1373+
- Value: 0x1
1374+
- Value: 0x1
1375+
- Value: 0x1
1376+
1377+
# DW_TAG_formal_parameter
1378+
# DW_AT_name [DW_FORM_strp] ("arg")
1379+
- AbbrCode: 0x5
1380+
Values:
1381+
- Value: 0x17
1382+
1383+
# DW_TAG_formal_parameter
1384+
# DW_AT_name [DW_FORM_strp] ("self")
1385+
# DW_AT_artificial
1386+
- AbbrCode: 0x6
1387+
Values:
1388+
- Value: 0x12
1389+
- Value: 0x1
1390+
1391+
- AbbrCode: 0x0
1392+
- AbbrCode: 0x0
1393+
1394+
# DW_TAG_subprogram
1395+
# DW_AT_object_pointer [DW_FORM_implicit_const] (0)
1396+
# DW_AT_name [DW_FORM_strp] ("func")
1397+
- AbbrCode: 0x4
1398+
Values:
1399+
- Value: 0x8
1400+
- Value: 0x1
1401+
- Value: 0x1
1402+
- Value: 0x1
1403+
1404+
# DW_TAG_formal_parameter
1405+
# DW_AT_name [DW_FORM_strp] ("this")
1406+
# DW_AT_artificial
1407+
- AbbrCode: 0x6
1408+
Values:
1409+
- Value: 0xd
1410+
- Value: 0x1
1411+
1412+
# DW_TAG_formal_parameter
1413+
# DW_AT_name [DW_FORM_strp] ("arg")
1414+
- AbbrCode: 0x5
1415+
Values:
1416+
- Value: 0x17
1417+
1418+
- AbbrCode: 0x0
1419+
- AbbrCode: 0x0
1420+
...
1421+
)";
1422+
1423+
YAMLModuleTester t(yamldata);
1424+
1425+
DWARFUnit *unit = t.GetDwarfUnit();
1426+
ASSERT_NE(unit, nullptr);
1427+
const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
1428+
ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
1429+
ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
1430+
DWARFDIE cu_die(unit, cu_entry);
1431+
1432+
auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast");
1433+
auto &ast_ctx = *holder->GetAST();
1434+
DWARFASTParserClangStub ast_parser(ast_ctx);
1435+
1436+
auto context_die = cu_die.GetFirstChild();
1437+
ASSERT_TRUE(context_die.IsValid());
1438+
ASSERT_EQ(context_die.Tag(), DW_TAG_structure_type);
1439+
1440+
auto sub1 = context_die.GetFirstChild();
1441+
ASSERT_TRUE(sub1.IsValid());
1442+
ASSERT_EQ(sub1.Tag(), DW_TAG_subprogram);
1443+
1444+
auto sub2 = sub1.GetSibling();
1445+
ASSERT_TRUE(sub2.IsValid());
1446+
ASSERT_EQ(sub2.Tag(), DW_TAG_subprogram);
1447+
1448+
// Object parameter is at constant index 1
1449+
{
1450+
auto param_die = sub1.GetFirstChild().GetSibling();
1451+
ASSERT_TRUE(param_die.IsValid());
1452+
1453+
EXPECT_EQ(param_die, ast_parser.GetCXXObjectParameter(sub1, context_die));
1454+
}
1455+
1456+
// Object parameter is at constant index 0
1457+
{
1458+
auto param_die = sub2.GetFirstChild();
1459+
ASSERT_TRUE(param_die.IsValid());
1460+
1461+
EXPECT_EQ(param_die,
1462+
ast_parser.GetCXXObjectParameter(param_die, context_die));
1463+
}
1464+
}

0 commit comments

Comments
 (0)