Skip to content

Commit 20e8759

Browse files
committed
libdrgn: linux_kernel: handle module section/note changes in Linux 6.14
Linux 6.14 refactored how module sections and notes are stored [1], removing explicit array lengths in favor of sysfs's existing null-terminated arrays. Update our section and note reading to handle that. 1: https://lore.kernel.org/all/20241227-sysfs-const-bin_attr-module-v2-0-e267275f0f37@weissschuh.net/. Signed-off-by: Omar Sandoval <[email protected]>
1 parent 4dca429 commit 20e8759

File tree

1 file changed

+142
-42
lines changed

1 file changed

+142
-42
lines changed

libdrgn/linux_kernel.c

Lines changed: 142 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,40 +1457,83 @@ kernel_module_set_build_id(struct drgn_module *module,
14571457
_cleanup_free_ void *buf = NULL;
14581458
size_t capacity = 0;
14591459

1460-
// n = mod->notes_attrs->notes
1461-
uint64_t n;
14621460
err = drgn_object_member(&attrs, module_obj, "notes_attrs");
1463-
if (err)
1464-
return err;
1465-
err = drgn_object_member_dereference(&tmp, &attrs, "notes");
1466-
if (err)
1467-
return err;
1468-
err = drgn_object_read_unsigned(&tmp, &n);
14691461
if (err)
14701462
return err;
14711463

1472-
// attrs = mod->notes_attrs->attrs
1473-
err = drgn_object_member_dereference(&attrs, &attrs, "attrs");
1474-
if (err)
1464+
bool group = true;
1465+
uint64_t n;
1466+
err = drgn_object_member_dereference(&attrs, &attrs, "grp");
1467+
if (!err) {
1468+
// Since Linux kernel commit 4723f16de64e ("module: sysfs: Add
1469+
// notes attributes through attribute_group") (in v6.14), we
1470+
// have to iterate over struct attribute_group::bin_attrs, a
1471+
// null-terminated array of struct bin_attribute pointers.
1472+
1473+
// attr = mod->notes_attrs->grp.bin_attrs
1474+
err = drgn_object_member(&attrs, &attrs, "bin_attrs");
1475+
if (err)
1476+
return err;
1477+
} else if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
1478+
// Before that, there was no struct attribute_group for notes,
1479+
// so we iterate over struct module_notes_attrs::attrs, an array
1480+
// of struct bin_attribute with a length given by struct
1481+
// module_notes_attrs::notes.
1482+
group = false;
1483+
// n = mod->notes_attrs->notes
1484+
err = drgn_object_member_dereference(&tmp, &attrs, "notes");
1485+
if (err)
1486+
return err;
1487+
err = drgn_object_read_unsigned(&tmp, &n);
1488+
if (err)
1489+
return err;
1490+
1491+
// attrs = mod->notes_attrs->attrs
1492+
err = drgn_object_member_dereference(&attrs, &attrs, "attrs");
1493+
if (err)
1494+
return err;
1495+
} else {
14751496
return err;
1497+
}
14761498

1477-
for (uint64_t i = 0; i < n; i++) {
1499+
// If we're not using struct attribute_group, we know how many
1500+
// attributes there are.
1501+
for (uint64_t i = 0; group || i < n; i++) {
14781502
// attr = attrs[i]
14791503
err = drgn_object_subscript(&attr, &attrs, i);
14801504
if (err)
14811505
return err;
14821506

1483-
// address = attr.private
1484-
err = drgn_object_member(&tmp, &attr, "private");
1507+
if (group) {
1508+
// If we're using struct attribute_group, we stop when
1509+
// we hit a NULL pointer.
1510+
err = drgn_object_read(&attr, &attr);
1511+
if (err)
1512+
return err;
1513+
bool truthy;
1514+
err = drgn_object_bool(&attr, &truthy);
1515+
if (err)
1516+
return err;
1517+
if (!truthy)
1518+
break;
1519+
} else {
1520+
// attr = &attrs[i]
1521+
err = drgn_object_address_of(&attr, &attr);
1522+
if (err)
1523+
return err;
1524+
}
1525+
1526+
// address = attr->private
1527+
err = drgn_object_member_dereference(&tmp, &attr, "private");
14851528
if (err)
14861529
return err;
14871530
uint64_t address;
14881531
err = drgn_object_read_unsigned(&tmp, &address);
14891532
if (err)
14901533
return err;
14911534

1492-
// size = attr.size
1493-
err = drgn_object_member(&tmp, &attr, "size");
1535+
// size = attr->size
1536+
err = drgn_object_member_dereference(&tmp, &attr, "size");
14941537
if (err)
14951538
return err;
14961539
uint64_t size;
@@ -1633,50 +1676,107 @@ kernel_module_set_section_addresses(struct drgn_module *module,
16331676
if (err)
16341677
return err;
16351678

1636-
// i = mod->sect_attrs->nsections
1679+
bool group = true;
1680+
uint64_t nsections;
16371681
err = drgn_object_member_dereference(&tmp, &attrs, "nsections");
1638-
if (err)
1639-
return err;
1640-
uint64_t i;
1641-
err = drgn_object_read_unsigned(&tmp, &i);
1642-
if (err)
1643-
return err;
1682+
if (drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
1683+
// Since Linux kernel commit d8959b947a8d ("module: sysfs: Drop
1684+
// member 'module_sect_attrs::nsections'") (in v6.14), we have
1685+
// to iterate over struct attribute_group::bin_attrs, a
1686+
// null-terminated array of struct bin_attribute pointers.
1687+
1688+
// attrs = mod->sect_attrs->grp.bin_attrs
1689+
err = drgn_object_member_dereference(&attrs, &attrs, "grp");
1690+
if (err)
1691+
return err;
1692+
err = drgn_object_member(&attrs, &attrs, "bin_attrs");
1693+
if (err)
1694+
return err;
1695+
} else if (!err) {
1696+
// Before that, struct module_sect_attrs::grp still exists.
1697+
// However, since Linux kernel commit ed66f991bb19 ("module:
1698+
// Refactor section attr into bin attribute") (in v5.8), the
1699+
// sections are in struct attribute_group::bin_attrs, and before
1700+
// that, they're in struct attribute_group::attrs. Additionally,
1701+
// we'd then have to get the containing struct module_sect_attr
1702+
// to get the section address.
1703+
//
1704+
// Instead, it's easier to iterate over struct
1705+
// module_sect_attrs::attrs, an array of struct module_sect_attr
1706+
// with a length given by struct module_sect_attrs::nsections.
1707+
group = false;
1708+
// nsections = mod->sect_attrs->nsections
1709+
err = drgn_object_read_unsigned(&tmp, &nsections);
1710+
if (err)
1711+
return err;
16441712

1645-
// attrs = mod->sect_attrs->attrs
1646-
err = drgn_object_member_dereference(&attrs, &attrs, "attrs");
1647-
if (err)
1713+
// attrs = mod->sect_attrs->attrs
1714+
err = drgn_object_member_dereference(&attrs, &attrs, "attrs");
1715+
if (err)
1716+
return err;
1717+
} else {
16481718
return err;
1719+
}
16491720

1650-
while (i-- > 0) {
1721+
// If we're not using struct attribute_group, we know how many
1722+
// attributes there are.
1723+
for (uint64_t i = 0; group || i < nsections; i++) {
16511724
// attr = attrs[i]
16521725
err = drgn_object_subscript(&attr, &attrs, i);
16531726
if (err)
16541727
return err;
16551728

1656-
// address = attr.address
1657-
err = drgn_object_member(&tmp, &attr, "address");
1658-
if (err)
1659-
return err;
1729+
if (group) {
1730+
// If we're using struct attribute_group, we stop when
1731+
// we hit a NULL pointer.
1732+
err = drgn_object_read(&attr, &attr);
1733+
if (err)
1734+
return err;
1735+
bool truthy;
1736+
err = drgn_object_bool(&attr, &truthy);
1737+
if (err)
1738+
return err;
1739+
if (!truthy)
1740+
break;
1741+
// Since Linux kernel commit 4b2c11e4aaf7 ("module:
1742+
// sysfs: Drop member 'module_sect_attr::address'") (in
1743+
// v6.14), the section address is in struct
1744+
// bin_attribute::private.
1745+
err = drgn_object_member_dereference(&tmp, &attr,
1746+
"private");
1747+
} else {
1748+
// Before that, the section address is in struct
1749+
// module_sect_attr::address.
1750+
err = drgn_object_member(&tmp, &attr, "address");
1751+
if (err)
1752+
return err;
1753+
}
16601754
uint64_t address;
16611755
err = drgn_object_read_unsigned(&tmp, &address);
16621756
if (err)
16631757
return err;
16641758

1665-
// Since Linux kernel commit ed66f991bb19 ("module: Refactor
1666-
// section attr into bin attribute") (in v5.8), the section name
1667-
// is module_sect_attr.battr.attr.name. Before that, it is
1668-
// simply module_sect_attr.name.
1669-
1670-
// attr = attr.battr.attr
1671-
err = drgn_object_member(&attr, &attr, "battr");
1672-
if (!err) {
1673-
err = drgn_object_member(&attr, &attr, "attr");
1759+
if (group) {
1760+
// attr = attr->attr
1761+
err = drgn_object_member_dereference(&attr, &attr,
1762+
"attr");
16741763
if (err)
16751764
return err;
16761765
} else {
1677-
if (err->code != DRGN_ERROR_LOOKUP)
1766+
// Since Linux kernel commit ed66f991bb19 ("module:
1767+
// Refactor section attr into bin attribute") (in v5.8),
1768+
// the section name is module_sect_attr.battr.attr.name.
1769+
// Before that, it is simply module_sect_attr.name.
1770+
1771+
// attr = attr.battr.attr
1772+
err = drgn_object_member(&attr, &attr, "battr");
1773+
if (!err) {
1774+
err = drgn_object_member(&attr, &attr, "attr");
1775+
if (err)
1776+
return err;
1777+
} else if (!drgn_error_catch(&err, DRGN_ERROR_LOOKUP)) {
16781778
return err;
1679-
drgn_error_destroy(err);
1779+
}
16801780
}
16811781
err = drgn_object_member(&tmp, &attr, "name");
16821782
if (err)

0 commit comments

Comments
 (0)