Hi, here is a refreshed patch against the dpkg main branch.
-- Benjamin Drung Debian & Ubuntu Developer
From f7b74e8c3c58e865197e3593c046b0e5e8ca37bb Mon Sep 17 00:00:00 2001 From: Benjamin Drung <[email protected]> Date: Wed, 1 Jul 2026 12:11:20 +0200 Subject: [PATCH] dpkg-buildflags: enable ELF package note metadata Following the https://systemd.io/ELF_PACKAGE_METADATA/ add a new qa flag, enable by default, that adds this package metadata ELF note to every binary being built, to ease identification, especially in the case of a coredump. Since the ELF package note metadata changes the build ID, include only "static" data and exclude the package version (as agreed at DebConf 25). Closes: #1117999 LP: #2071468 --- man/dpkg-buildflags.pod | 11 ++++++ scripts/Dpkg/Vendor/Debian.pm | 64 +++++++++++++++++++++++++++++++++++ scripts/t/Dpkg_BuildFlags.t | 12 ++++++- scripts/t/mk.t | 4 ++- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/man/dpkg-buildflags.pod b/man/dpkg-buildflags.pod index a7e936f8d..3e8c2d6af 100644 --- a/man/dpkg-buildflags.pod +++ b/man/dpkg-buildflags.pod @@ -611,6 +611,17 @@ Disabled by default. Supported since dpkg 1.17.14. +=item B<elfpackagemetadata> + +This setting adds an ELF note containing package metadata to every ELF binary +being built. If the $DEB_BUILD_DEBUG_INFO_URL environment variable is defined, +it will be used to include the value as a debuginfod URL. This follows the +specification defined at: https://systemd.io/ELF_PACKAGE_METADATA/ + +Enabled by default. + +Supported since dpkg 1.22.20. + =back =head2 optimize diff --git a/scripts/Dpkg/Vendor/Debian.pm b/scripts/Dpkg/Vendor/Debian.pm index 028ed272a..a1697e7dc 100644 --- a/scripts/Dpkg/Vendor/Debian.pm +++ b/scripts/Dpkg/Vendor/Debian.pm @@ -136,6 +136,7 @@ sub set_build_features { bug => undef, 'bug-implicit-func' => undef, canary => 0, + elfpackagemetadata => 1, }, reproducible => { timeless => 1, @@ -516,6 +517,10 @@ sub add_build_flags { $flags->append('LDFLAGS', "-Wl,-z,deb-canary-${id}"); } + if ($flags->use_feature('qa', 'elfpackagemetadata')) { + add_elf_package_metadata($flags); + } + ## Area: reproducible # Warn when the __TIME__, __DATE__ and __TIMESTAMP__ macros are used. @@ -680,6 +685,65 @@ sub add_build_flags { } } +sub add_elf_package_metadata { + my ($flags) = @_; + my $arch; + my $pkgsrc; + + if (!defined $ENV{DEB_HOST_ARCH}) { + require Dpkg::Arch; + $arch = Dpkg::Arch::get_host_arch(); + } else { + $arch = $ENV{DEB_HOST_ARCH}; + } + + if (!defined $ENV{DEB_SOURCE}) { + if (! -r 'debian/changelog') { + warning(g_('debian/changelog not found. Not setting ELF package metadata parameter.')); + return; + } + + require Dpkg::Changelog::Debian; + my $pkgchangelog = Dpkg::Changelog::Debian->new(range => { "count" => 1 }); + $pkgchangelog->load('debian/changelog'); + my $chgentry = @{$pkgchangelog}[0]; + $pkgsrc = $chgentry->get_source(); + } else { + $pkgsrc = $ENV{DEB_SOURCE}; + } + + if (! -f '/usr/lib/os-release') { + warning(g_('/usr/lib/os-release not found. Not setting ELF package metadata parameter.')); + return; + } + my $os_id = ''; + open my $os_release, '<', '/usr/lib/os-release' + or syserr(g_('failed to read /usr/lib/os-release')); + while (<$os_release>) { + chomp; + # Ensure any quotes are removed, as we don't want to embed them in JSON + if (m/^ID=(.*)/) { + $os_id = $1; + $os_id =~ tr/"//d; + } + } + close $os_release or syserr(g_('failed to close /usr/lib/os-release')); + if ($os_id eq '') { + warning(g_('/usr/lib/os-release does not set ID. Not setting ELF package metadata parameter.')); + return; + } + + # Per https://systemd.io/ELF_PACKAGE_METADATA/ + my $package_metadata = "{%22type%22:%22deb%22%2C%22os%22:%22$os_id%22%2C%22name%22:%22$pkgsrc%22%2C%22architecture%22:%22$arch%22"; + # The debuginfod URL is optional, skip it if not available. + if ($ENV{DEB_BUILD_DEBUG_INFO_URL}) { + $package_metadata .= "%2C%22debugInfoUrl%22:%22$ENV{DEB_BUILD_DEBUG_INFO_URL}%22"; + } + $package_metadata .= "}"; + $flags->append('LDFLAGS', "-Wl,--package-metadata=$package_metadata"); + return; +} + sub _build_tainted_by { my $self = shift; my %tainted; diff --git a/scripts/t/Dpkg_BuildFlags.t b/scripts/t/Dpkg_BuildFlags.t index 011a50717..07d8a15d2 100644 --- a/scripts/t/Dpkg_BuildFlags.t +++ b/scripts/t/Dpkg_BuildFlags.t @@ -15,7 +15,7 @@ use v5.36; -use Test::More tests => 118; +use Test::More tests => 119; BEGIN { $ENV{DEB_BUILD_ARCH} = 'amd64'; @@ -121,6 +121,7 @@ my %known_features = ( bug bug-implicit-func canary + elfpackagemetadata ) ], reproducible => [ qw( fixdebugpath @@ -316,4 +317,13 @@ test_has_noflag($bf, 'CPPFLAGS', '-D_TIME_BITS=64'); test_has_noflag($bf, 'CPPFLAGS', '-U_TIME_BITS'); test_has_flag($bf, 'CFLAGS', '-Werror=implicit-function-declaration'); +# ELF package metadata +$bf = Dpkg::BuildFlags->new(); +my %qa_features = $bf->get_features('qa'); +if ($qa_features{'elfpackagemetadata'} && -r 'debian/changelog') { + test_has_flag($bf, 'LDFLAGS', '-Wl,--package-metadata=\{*'); +} else { + test_has_noflag($bf, 'LDFLAGS', '-Wl,--package-metadata*'); +} + # TODO: Add more test cases. diff --git a/scripts/t/mk.t b/scripts/t/mk.t index 811b7be7e..d77a5adba 100644 --- a/scripts/t/mk.t +++ b/scripts/t/mk.t @@ -26,7 +26,7 @@ use Dpkg::IPC; use Dpkg::Vendor; my $srcdir = rel2abs($ENV{srcdir} || '.'); -my $datadir = test_get_data_path(); +my $datadir = rel2abs(test_get_data_path()); # Turn these into absolute names so that we can safely switch to the test # directory with «make -C». @@ -74,6 +74,8 @@ sub cmd_get_vars { # Test makefiles. +chdir($ENV{DEB_BUILD_PATH}); + my %arch = cmd_get_vars($ENV{PERL}, "$srcdir/dpkg-architecture.pl", '-f'); while (my ($k, $v) = each %arch) { -- 2.53.0

