Skip to content

Commit 1bc6326

Browse files
authored
[lldb][DWARFASTParserClang] Support constant index encoding of DW_AT_object_pointer (#144998)
Starting with #124790, Clang emits `DW_AT_object_pointer` encoded as integer constants rather than DIE references. This patch accounts for this. Depends on #145328 and #145126
1 parent 081adc1 commit 1bc6326

File tree

3 files changed

+241
-17
lines changed

3 files changed

+241
-17
lines changed

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

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

170-
if (DWARFDIE object_parameter =
171-
subprogram.GetAttributeValueAsReferenceDIE(DW_AT_object_pointer))
172-
return object_parameter;
170+
// The DW_AT_object_pointer may be either encoded as a reference to a DIE,
171+
// in which case that's the object parameter we want. Or it can be a constant
172+
// index of the parameter.
173+
std::optional<size_t> object_pointer_index;
174+
DWARFFormValue form_value;
175+
if (subprogram.GetDIE()->GetAttributeValue(
176+
subprogram.GetCU(), DW_AT_object_pointer, form_value,
177+
/*end_attr_offset_ptr=*/nullptr, /*check_elaborating_dies=*/true)) {
178+
if (auto ref = form_value.Reference())
179+
return ref;
180+
181+
object_pointer_index = form_value.Unsigned();
182+
}
183+
184+
// Try to find the DW_TAG_formal_parameter via object_pointer_index.
185+
DWARFDIE object_pointer;
186+
size_t param_index = 0;
187+
for (const auto &child : subprogram.children()) {
188+
if (child.Tag() != DW_TAG_formal_parameter)
189+
continue;
190+
191+
if (param_index == object_pointer_index.value_or(0)) {
192+
object_pointer = child;
193+
break;
194+
}
195+
196+
++param_index;
197+
}
198+
199+
// No formal parameter found for object pointer index.
200+
// Nothing to be done.
201+
if (!object_pointer)
202+
return {};
203+
204+
// We found the object pointer encoded via DW_AT_object_pointer.
205+
// No need for the remaining heuristics.
206+
if (object_pointer_index)
207+
return object_pointer;
173208

174209
// If no DW_AT_object_pointer was specified, assume the implicit object
175210
// parameter is the first parameter to the function, is called "this" and is
@@ -178,16 +213,6 @@ DWARFASTParserClang::GetObjectParameter(const DWARFDIE &subprogram,
178213
if (!decl_ctx_die.IsStructUnionOrClass())
179214
return {};
180215

181-
auto children = subprogram.children();
182-
auto it = llvm::find_if(children, [](const DWARFDIE &child) {
183-
return child.Tag() == DW_TAG_formal_parameter;
184-
});
185-
186-
if (it == children.end())
187-
return {};
188-
189-
DWARFDIE object_pointer = *it;
190-
191216
if (!object_pointer.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
192217
return {};
193218

lldb/test/Shell/SymbolFile/DWARF/x86/explicit-member-function-quals.cpp

Lines changed: 9 additions & 4 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,10 +13,10 @@
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 {

lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,3 +1423,197 @@ TEST_F(DWARFASTParserClangTests, TestParseSubroutine_ParameterCreation) {
14231423
EXPECT_EQ(func->getParamDecl(1)->getDeclContext(), func);
14241424
EXPECT_EQ(func->getParamDecl(1)->getName(), "namedParam");
14251425
}
1426+
1427+
TEST_F(DWARFASTParserClangTests, TestObjectPointer_IndexEncoding) {
1428+
// This tests the behaviour of DWARFASTParserClang
1429+
// for DW_TAG_subprogram definitions which have a DW_AT_object_pointer
1430+
// that encodes a constant index (instead of a DIE reference).
1431+
1432+
const char *yamldata = R"(
1433+
--- !ELF
1434+
FileHeader:
1435+
Class: ELFCLASS64
1436+
Data: ELFDATA2LSB
1437+
Type: ET_EXEC
1438+
Machine: EM_AARCH64
1439+
DWARF:
1440+
debug_str:
1441+
- Context
1442+
- func
1443+
- this
1444+
- self
1445+
- arg
1446+
debug_abbrev:
1447+
- ID: 0
1448+
Table:
1449+
- Code: 0x1
1450+
Tag: DW_TAG_compile_unit
1451+
Children: DW_CHILDREN_yes
1452+
Attributes:
1453+
- Attribute: DW_AT_language
1454+
Form: DW_FORM_data2
1455+
- Code: 0x2
1456+
Tag: DW_TAG_structure_type
1457+
Children: DW_CHILDREN_yes
1458+
Attributes:
1459+
- Attribute: DW_AT_name
1460+
Form: DW_FORM_strp
1461+
- Code: 0x3
1462+
Tag: DW_TAG_subprogram
1463+
Children: DW_CHILDREN_yes
1464+
Attributes:
1465+
- Attribute: DW_AT_name
1466+
Form: DW_FORM_strp
1467+
- Attribute: DW_AT_declaration
1468+
Form: DW_FORM_flag_present
1469+
- Attribute: DW_AT_object_pointer
1470+
Form: DW_FORM_implicit_const
1471+
Value: 1
1472+
- Attribute: DW_AT_external
1473+
Form: DW_FORM_flag_present
1474+
- Code: 0x4
1475+
Tag: DW_TAG_subprogram
1476+
Children: DW_CHILDREN_yes
1477+
Attributes:
1478+
- Attribute: DW_AT_name
1479+
Form: DW_FORM_strp
1480+
- Attribute: DW_AT_declaration
1481+
Form: DW_FORM_flag_present
1482+
- Attribute: DW_AT_object_pointer
1483+
Form: DW_FORM_implicit_const
1484+
Value: 0
1485+
- Attribute: DW_AT_external
1486+
Form: DW_FORM_flag_present
1487+
1488+
- Code: 0x5
1489+
Tag: DW_TAG_formal_parameter
1490+
Children: DW_CHILDREN_no
1491+
Attributes:
1492+
- Attribute: DW_AT_name
1493+
Form: DW_FORM_strp
1494+
1495+
- Code: 0x6
1496+
Tag: DW_TAG_formal_parameter
1497+
Children: DW_CHILDREN_no
1498+
Attributes:
1499+
- Attribute: DW_AT_name
1500+
Form: DW_FORM_strp
1501+
- Attribute: DW_AT_artificial
1502+
Form: DW_FORM_flag_present
1503+
1504+
debug_info:
1505+
- Version: 5
1506+
UnitType: DW_UT_compile
1507+
AddrSize: 8
1508+
Entries:
1509+
1510+
# DW_TAG_compile_unit
1511+
# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus)
1512+
1513+
- AbbrCode: 0x1
1514+
Values:
1515+
- Value: 0x04
1516+
1517+
# DW_TAG_structure_type
1518+
# DW_AT_name [DW_FORM_strp] ("Context")
1519+
1520+
- AbbrCode: 0x2
1521+
Values:
1522+
- Value: 0x0
1523+
1524+
# DW_TAG_subprogram
1525+
# DW_AT_name [DW_FORM_strp] ("func")
1526+
# DW_AT_object_pointer [DW_FORM_implicit_const] (1)
1527+
- AbbrCode: 0x3
1528+
Values:
1529+
- Value: 0x8
1530+
- Value: 0x1
1531+
- Value: 0x1
1532+
- Value: 0x1
1533+
1534+
# DW_TAG_formal_parameter
1535+
# DW_AT_name [DW_FORM_strp] ("arg")
1536+
- AbbrCode: 0x5
1537+
Values:
1538+
- Value: 0x17
1539+
1540+
# DW_TAG_formal_parameter
1541+
# DW_AT_name [DW_FORM_strp] ("self")
1542+
# DW_AT_artificial
1543+
- AbbrCode: 0x6
1544+
Values:
1545+
- Value: 0x12
1546+
- Value: 0x1
1547+
1548+
- AbbrCode: 0x0
1549+
1550+
# DW_TAG_subprogram
1551+
# DW_AT_object_pointer [DW_FORM_implicit_const] (0)
1552+
# DW_AT_name [DW_FORM_strp] ("func")
1553+
- AbbrCode: 0x4
1554+
Values:
1555+
- Value: 0x8
1556+
- Value: 0x1
1557+
- Value: 0x1
1558+
- Value: 0x1
1559+
1560+
# DW_TAG_formal_parameter
1561+
# DW_AT_name [DW_FORM_strp] ("this")
1562+
# DW_AT_artificial
1563+
- AbbrCode: 0x6
1564+
Values:
1565+
- Value: 0xd
1566+
- Value: 0x1
1567+
1568+
# DW_TAG_formal_parameter
1569+
# DW_AT_name [DW_FORM_strp] ("arg")
1570+
- AbbrCode: 0x5
1571+
Values:
1572+
- Value: 0x17
1573+
1574+
- AbbrCode: 0x0
1575+
- AbbrCode: 0x0
1576+
...
1577+
)";
1578+
1579+
YAMLModuleTester t(yamldata);
1580+
1581+
DWARFUnit *unit = t.GetDwarfUnit();
1582+
ASSERT_NE(unit, nullptr);
1583+
const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
1584+
ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
1585+
ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus);
1586+
DWARFDIE cu_die(unit, cu_entry);
1587+
1588+
auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast");
1589+
auto &ast_ctx = *holder->GetAST();
1590+
DWARFASTParserClangStub ast_parser(ast_ctx);
1591+
1592+
auto context_die = cu_die.GetFirstChild();
1593+
ASSERT_TRUE(context_die.IsValid());
1594+
ASSERT_EQ(context_die.Tag(), DW_TAG_structure_type);
1595+
1596+
auto sub1 = context_die.GetFirstChild();
1597+
ASSERT_TRUE(sub1.IsValid());
1598+
ASSERT_EQ(sub1.Tag(), DW_TAG_subprogram);
1599+
1600+
auto sub2 = sub1.GetSibling();
1601+
ASSERT_TRUE(sub2.IsValid());
1602+
ASSERT_EQ(sub2.Tag(), DW_TAG_subprogram);
1603+
1604+
// Object parameter is at constant index 1
1605+
{
1606+
auto param_die = sub1.GetFirstChild().GetSibling();
1607+
ASSERT_TRUE(param_die.IsValid());
1608+
1609+
EXPECT_EQ(param_die, ast_parser.GetObjectParameter(sub1, context_die));
1610+
}
1611+
1612+
// Object parameter is at constant index 0
1613+
{
1614+
auto param_die = sub2.GetFirstChild();
1615+
ASSERT_TRUE(param_die.IsValid());
1616+
1617+
EXPECT_EQ(param_die, ast_parser.GetObjectParameter(sub2, context_die));
1618+
}
1619+
}

0 commit comments

Comments
 (0)