On Mon, 13 Oct 2025 15:53:16 +0200 Benjamin Drung <[email protected]>
wrote:
> Package: dpkg
> Version: 1.22.21
> Severity: normal
> Tags: patch
> X-Debbugs-Cc: [email protected]
> 
> Dear Maintainer,
> 
> as discussed and agreed on at DebConf 25, please add ELF package note
> metadata following the
>
https://systemd.io/PACKAGE_METADATA_FOR_EXECUTABLE_FILES/ specification.

> 
> A tested patch is attached.

Here is an updated patch with following changes:

* fix extra comma when DEB_BUILD_DEBUG_INFO_URL is set
* fix scripts/t/mk.t test case (i.e. make debian/changelog accessible)

-- 
Benjamin Drung
Debian & Ubuntu Developer
From 322086638d888fc604fe29db86fa196d7deda70c Mon Sep 17 00:00:00 2001
From: Benjamin Drung <[email protected]>
Date: Tue, 18 Nov 2025 19:01:53 +0100
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       |  8 +++++
 scripts/Dpkg/Vendor/Debian.pm | 64 +++++++++++++++++++++++++++++++++++
 scripts/t/Dpkg_BuildFlags.t   | 12 ++++++-
 scripts/t/mk.t                |  4 ++-
 4 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/man/dpkg-buildflags.pod b/man/dpkg-buildflags.pod
index 7a759eb7a..33be2555b 100644
--- a/man/dpkg-buildflags.pod
+++ b/man/dpkg-buildflags.pod
@@ -545,6 +545,14 @@ B<OBJCFLAGS>, B<CXXFLAGS> and B<OBJCXXFLAGS> with flags set
 to B<-D__DEB_CANARY_>I<flag>_I<random-id>B<__>, and
 B<LDFLAGS> set to B<-Wl,-z,deb-canary->I<random-id>.
 
+=item B<elfpackagemetadata>
+
+This setting (since dpkg 1.23.0; enabled by default) 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/
+
 =back
 
 =head2 optimize
diff --git a/scripts/Dpkg/Vendor/Debian.pm b/scripts/Dpkg/Vendor/Debian.pm
index f7272ad61..a002d7a9f 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.
@@ -681,6 +686,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.51.0

Reply via email to