diff mbox series

[v2] gdb/systemd: enable minidebuginfo support conditionally

Message ID 20231205133754.906479-1-ecordonnier@snap.com
State Accepted, archived
Commit 0d2df803bebfd7e832ab7da54c4dacaaeeb424a9
Headers show
Series [v2] gdb/systemd: enable minidebuginfo support conditionally | expand

Commit Message

Etienne Cordonnier Dec. 5, 2023, 1:37 p.m. UTC
From: Etienne Cordonnier <ecordonnier@snap.com>

Enabling minidebuginfo is not useful if gdb and systemd-coredump
are unable to parse it.

In order to parse it, gdb needs xz support. Systemd needs coredump enabled, as
well as elfutil enabled as well (systemd-coredump loads libdw which is part of elfutils using dlopen).

Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
---
 meta/classes-global/package.bbclass           |  2 +-
 meta/lib/oe/package.py                        |  2 +-
 meta/lib/oeqa/runtime/cases/systemd.py        | 21 +++++++++++++++++++
 meta/lib/oeqa/selftest/cases/minidebuginfo.py |  2 +-
 meta/recipes-core/systemd/systemd_254.4.bb    |  1 +
 .../elfutils/elfutils_0.189.bb                |  4 +++-
 meta/recipes-devtools/gdb/gdb-common.inc      |  4 +++-
 7 files changed, 31 insertions(+), 5 deletions(-)

Comments

Etienne Cordonnier Dec. 5, 2023, 1:40 p.m. UTC | #1
Version 2 of the patch: I implemented the feedback of Richard (convert
PACKAGE_MINIDEBUGINFO to a DISTRO_FEATURES), and added a runtime test.
This was my local.conf used for testing (with "bitbake -v -c testimage
core-image-sato"):

DISTRO_FEATURES:append = " minidebuginfo"
IMAGE_CLASSES += "testimage"
TEST_SUITES += "ping ssh systemd"

DISTRO_FEATURES:append = " systemd usrmerge"
DISTRO_FEATURES_BACKFILL_CONSIDERED += "sysvinit"
VIRTUAL-RUNTIME_init_manager = "systemd"
VIRTUAL-RUNTIME_initscripts = "systemd-compat-units"

Etienne

On Tue, Dec 5, 2023 at 2:38 PM <ecordonnier@snap.com> wrote:

> From: Etienne Cordonnier <ecordonnier@snap.com>
>
> Enabling minidebuginfo is not useful if gdb and systemd-coredump
> are unable to parse it.
>
> In order to parse it, gdb needs xz support. Systemd needs coredump
> enabled, as
> well as elfutil enabled as well (systemd-coredump loads libdw which is
> part of elfutils using dlopen).
>
> Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
> ---
>  meta/classes-global/package.bbclass           |  2 +-
>  meta/lib/oe/package.py                        |  2 +-
>  meta/lib/oeqa/runtime/cases/systemd.py        | 21 +++++++++++++++++++
>  meta/lib/oeqa/selftest/cases/minidebuginfo.py |  2 +-
>  meta/recipes-core/systemd/systemd_254.4.bb    |  1 +
>  .../elfutils/elfutils_0.189.bb                |  4 +++-
>  meta/recipes-devtools/gdb/gdb-common.inc      |  4 +++-
>  7 files changed, 31 insertions(+), 5 deletions(-)
>
> diff --git a/meta/classes-global/package.bbclass
> b/meta/classes-global/package.bbclass
> index 2ad820a81f..f56bca3542 100644
> --- a/meta/classes-global/package.bbclass
> +++ b/meta/classes-global/package.bbclass
> @@ -234,7 +234,7 @@ python () {
>          deps = ""
>          for dep in (d.getVar('PACKAGE_DEPENDS') or "").split():
>              deps += " %s:do_populate_sysroot" % dep
> -        if d.getVar('PACKAGE_MINIDEBUGINFO') == '1':
> +        if bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', True,
> False, d):
>              deps += ' xz-native:do_populate_sysroot'
>          d.appendVarFlag('do_package', 'depends', deps)
>
> diff --git a/meta/lib/oe/package.py b/meta/lib/oe/package.py
> index f69bf9c353..9a465eaa09 100644
> --- a/meta/lib/oe/package.py
> +++ b/meta/lib/oe/package.py
> @@ -1239,7 +1239,7 @@ def process_split_and_strip_files(d):
>          oe.utils.multiprocess_launch(oe.package.runstrip, sfiles, d)
>
>      # Build "minidebuginfo" and reinject it back into the stripped
> binaries
> -    if d.getVar('PACKAGE_MINIDEBUGINFO') == '1':
> +    if bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', True, False,
> d):
>          oe.utils.multiprocess_launch(inject_minidebuginfo,
> list(elffiles), d,
>                                       extraargs=(dvar, dv, d))
>
> diff --git a/meta/lib/oeqa/runtime/cases/systemd.py
> b/meta/lib/oeqa/runtime/cases/systemd.py
> index 37f295492d..4c581ba396 100644
> --- a/meta/lib/oeqa/runtime/cases/systemd.py
> +++ b/meta/lib/oeqa/runtime/cases/systemd.py
> @@ -5,6 +5,7 @@
>  #
>
>  import re
> +import threading
>  import time
>
>  from oeqa.runtime.case import OERuntimeTestCase
> @@ -136,6 +137,26 @@ class SystemdServiceTests(SystemdTest):
>              status = self.target.run('mount -oro,remount /')[0]
>              self.assertTrue(status == 0, msg='Remounting / as r/o failed')
>
> +    @skipIfNotFeature('minidebuginfo', 'Test requires minidebuginfo to be
> in DISTRO_FEATURES')
> +    @OEHasPackage(['busybox'])
> +    def test_systemd_coredump_minidebuginfo(self):
> +        """
> +        Verify that call-stacks generated by systemd-coredump contain
> symbolicated call-stacks,
> +        extracted from the minidebuginfo metadata (.gnu_debugdata elf
> section).
> +        """
> +        t_thread = threading.Thread(target=self.target.run, args=("ulimit
> -c unlimited && sleep 1000",))
> +        t_thread.start()
> +        time.sleep(1)
> +
> +        status, output = self.target.run('pidof sleep')
> +        # cause segfault on purpose
> +        self.target.run('kill -SEGV %s' % output)
> +        self.assertEqual(status, 0, msg = 'Not able to find process that
> runs sleep, output : %s' % output)
> +
> +        (status, output) = self.target.run('coredumpctl info')
> +        self.assertEqual(status, 0, msg='MiniDebugInfo Test failed: %s' %
> output)
> +        self.assertEqual('sleep_for_duration (busybox.nosuid' in output,
> True, msg='Call stack is missing minidebuginfo symbols (functions shown as
> "n/a"): %s' % output)
> +
>  class SystemdJournalTests(SystemdTest):
>
>      @OETestDepends(['systemd.SystemdBasicTests.test_systemd_basic'])
> diff --git a/meta/lib/oeqa/selftest/cases/minidebuginfo.py
> b/meta/lib/oeqa/selftest/cases/minidebuginfo.py
> index aa1f9fa1f7..2919f07939 100644
> --- a/meta/lib/oeqa/selftest/cases/minidebuginfo.py
> +++ b/meta/lib/oeqa/selftest/cases/minidebuginfo.py
> @@ -21,7 +21,7 @@ class Minidebuginfo(OESelftestTestCase):
>          bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME',
> 'READELF'], image)
>
>          self.write_config("""
> -PACKAGE_MINIDEBUGINFO = "1"
> +DISTRO_FEATURES:append = " minidebuginfo"
>  IMAGE_FSTYPES = "tar.bz2"
>  """)
>          bitbake("{} {}:do_addto_recipe_sysroot".format(image, binutils))
> diff --git a/meta/recipes-core/systemd/systemd_254.4.bb
> b/meta/recipes-core/systemd/systemd_254.4.bb
> index 4d68a3266a..0c12926bef 100644
> --- a/meta/recipes-core/systemd/systemd_254.4.bb
> +++ b/meta/recipes-core/systemd/systemd_254.4.bb
> @@ -67,6 +67,7 @@ PAM_PLUGINS = " \
>
>  PACKAGECONFIG ??= " \
>      ${@bb.utils.filter('DISTRO_FEATURES', 'acl audit efi ldconfig pam
> selinux smack usrmerge polkit seccomp', d)} \
> +    ${@bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', 'coredump
> elfutils', '', d)} \
>      ${@bb.utils.contains('DISTRO_FEATURES', 'wifi', 'rfkill', '', d)} \
>      ${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'xkbcommon', '', d)} \
>      ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', '',
> 'link-udev-shared', d)} \
> diff --git a/meta/recipes-devtools/elfutils/elfutils_0.189.bb
> b/meta/recipes-devtools/elfutils/elfutils_0.189.bb
> index d8bf82b022..d69828131e 100644
> --- a/meta/recipes-devtools/elfutils/elfutils_0.189.bb
> +++ b/meta/recipes-devtools/elfutils/elfutils_0.189.bb
> @@ -39,7 +39,9 @@ BUILD_CFLAGS += "-Wno-error=stringop-overflow"
>  DEPENDS_BZIP2 = "bzip2-replacement-native"
>  DEPENDS_BZIP2:class-target = "bzip2"
>
> -PACKAGECONFIG ??= "${@bb.utils.contains('DISTRO_FEATURES', 'debuginfod',
> 'debuginfod libdebuginfod', '', d)}"
> +PACKAGECONFIG ??= "${@bb.utils.contains('DISTRO_FEATURES', 'debuginfod',
> 'debuginfod libdebuginfod', '', d)} \
> +                   ${@bb.utils.contains('DISTRO_FEATURES',
> 'minidebuginfo', 'xz', '', d)} \
> +                  "
>  PACKAGECONFIG[bzip2] = "--with-bzlib,--without-bzlib,${DEPENDS_BZIP2}"
>  PACKAGECONFIG[xz] = "--with-lzma,--without-lzma,xz"
>  PACKAGECONFIG[zstd] = "--with-zstd,--without-zstd,zstd"
> diff --git a/meta/recipes-devtools/gdb/gdb-common.inc
> b/meta/recipes-devtools/gdb/gdb-common.inc
> index 3349719a6b..48dbb91463 100644
> --- a/meta/recipes-devtools/gdb/gdb-common.inc
> +++ b/meta/recipes-devtools/gdb/gdb-common.inc
> @@ -30,7 +30,9 @@ EXTRA_OECONF = "--disable-gdbtk --disable-x
> --disable-werror \
>                  --with-libgmp-prefix=${STAGING_EXECPREFIXDIR} \
>  "
>
> -PACKAGECONFIG ??= "readline ${@bb.utils.filter('DISTRO_FEATURES',
> 'debuginfod', d)} python"
> +PACKAGECONFIG ??= "readline ${@bb.utils.filter('DISTRO_FEATURES',
> 'debuginfod', d)} python \
> +                   ${@bb.utils.contains('DISTRO_FEATURES',
> 'minidebuginfo', 'xz', '', d)} \
> +                  "
>  # Use --without-system-readline to compile with readline 5.
>  PACKAGECONFIG[readline] =
> "--with-system-readline,--without-system-readline,readline"
>  PACKAGECONFIG[python] =
> "--with-python=${WORKDIR}/python,--without-python,python3,python3-codecs"
> --
> 2.34.1
>
>
Richard Purdie Dec. 7, 2023, 11:25 p.m. UTC | #2
On Tue, 2023-12-05 at 14:37 +0100, Etienne Cordonnier via
lists.openembedded.org wrote:
> From: Etienne Cordonnier <ecordonnier@snap.com>
> 
> Enabling minidebuginfo is not useful if gdb and systemd-coredump
> are unable to parse it.
> 
> In order to parse it, gdb needs xz support. Systemd needs coredump enabled, as
> well as elfutil enabled as well (systemd-coredump loads libdw which is part of elfutils using dlopen).
> 
> Signed-off-by: Etienne Cordonnier <ecordonnier@snap.com>
> ---
>  meta/classes-global/package.bbclass           |  2 +-
>  meta/lib/oe/package.py                        |  2 +-
>  meta/lib/oeqa/runtime/cases/systemd.py        | 21 +++++++++++++++++++
>  meta/lib/oeqa/selftest/cases/minidebuginfo.py |  2 +-
>  meta/recipes-core/systemd/systemd_254.4.bb    |  1 +
>  .../elfutils/elfutils_0.189.bb                |  4 +++-
>  meta/recipes-devtools/gdb/gdb-common.inc      |  4 +++-
>  7 files changed, 31 insertions(+), 5 deletions(-)

I merged this as I think it did improve things but adding a test change
to poky to enable it hasn't quite worked as I hoped.

I had to put a constraint around the test to ensure it only runs on
systemd images:

https://git.openembedded.org/openembedded-core/commit/?h=master-next&id=9c069e00a0867de11a6069b99a07d2c775848c10

and with that applied I then had this failure:

https://autobuilder.yoctoproject.org/typhoon/#/builders/101/builds/7000/steps/14/logs/stdio

I can queue the first patch but I'm not sure about the failure above.
Any ideas?

Cheers,

Richard
diff mbox series

Patch

diff --git a/meta/classes-global/package.bbclass b/meta/classes-global/package.bbclass
index 2ad820a81f..f56bca3542 100644
--- a/meta/classes-global/package.bbclass
+++ b/meta/classes-global/package.bbclass
@@ -234,7 +234,7 @@  python () {
         deps = ""
         for dep in (d.getVar('PACKAGE_DEPENDS') or "").split():
             deps += " %s:do_populate_sysroot" % dep
-        if d.getVar('PACKAGE_MINIDEBUGINFO') == '1':
+        if bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', True, False, d):
             deps += ' xz-native:do_populate_sysroot'
         d.appendVarFlag('do_package', 'depends', deps)
 
diff --git a/meta/lib/oe/package.py b/meta/lib/oe/package.py
index f69bf9c353..9a465eaa09 100644
--- a/meta/lib/oe/package.py
+++ b/meta/lib/oe/package.py
@@ -1239,7 +1239,7 @@  def process_split_and_strip_files(d):
         oe.utils.multiprocess_launch(oe.package.runstrip, sfiles, d)
 
     # Build "minidebuginfo" and reinject it back into the stripped binaries
-    if d.getVar('PACKAGE_MINIDEBUGINFO') == '1':
+    if bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', True, False, d):
         oe.utils.multiprocess_launch(inject_minidebuginfo, list(elffiles), d,
                                      extraargs=(dvar, dv, d))
 
diff --git a/meta/lib/oeqa/runtime/cases/systemd.py b/meta/lib/oeqa/runtime/cases/systemd.py
index 37f295492d..4c581ba396 100644
--- a/meta/lib/oeqa/runtime/cases/systemd.py
+++ b/meta/lib/oeqa/runtime/cases/systemd.py
@@ -5,6 +5,7 @@ 
 #
 
 import re
+import threading
 import time
 
 from oeqa.runtime.case import OERuntimeTestCase
@@ -136,6 +137,26 @@  class SystemdServiceTests(SystemdTest):
             status = self.target.run('mount -oro,remount /')[0]
             self.assertTrue(status == 0, msg='Remounting / as r/o failed')
 
+    @skipIfNotFeature('minidebuginfo', 'Test requires minidebuginfo to be in DISTRO_FEATURES')
+    @OEHasPackage(['busybox'])
+    def test_systemd_coredump_minidebuginfo(self):
+        """
+        Verify that call-stacks generated by systemd-coredump contain symbolicated call-stacks,
+        extracted from the minidebuginfo metadata (.gnu_debugdata elf section).
+        """
+        t_thread = threading.Thread(target=self.target.run, args=("ulimit -c unlimited && sleep 1000",))
+        t_thread.start()
+        time.sleep(1)
+
+        status, output = self.target.run('pidof sleep')
+        # cause segfault on purpose
+        self.target.run('kill -SEGV %s' % output)
+        self.assertEqual(status, 0, msg = 'Not able to find process that runs sleep, output : %s' % output)
+
+        (status, output) = self.target.run('coredumpctl info')
+        self.assertEqual(status, 0, msg='MiniDebugInfo Test failed: %s' % output)
+        self.assertEqual('sleep_for_duration (busybox.nosuid' in output, True, msg='Call stack is missing minidebuginfo symbols (functions shown as "n/a"): %s' % output)
+
 class SystemdJournalTests(SystemdTest):
 
     @OETestDepends(['systemd.SystemdBasicTests.test_systemd_basic'])
diff --git a/meta/lib/oeqa/selftest/cases/minidebuginfo.py b/meta/lib/oeqa/selftest/cases/minidebuginfo.py
index aa1f9fa1f7..2919f07939 100644
--- a/meta/lib/oeqa/selftest/cases/minidebuginfo.py
+++ b/meta/lib/oeqa/selftest/cases/minidebuginfo.py
@@ -21,7 +21,7 @@  class Minidebuginfo(OESelftestTestCase):
         bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME', 'READELF'], image)
 
         self.write_config("""
-PACKAGE_MINIDEBUGINFO = "1"
+DISTRO_FEATURES:append = " minidebuginfo"
 IMAGE_FSTYPES = "tar.bz2"
 """)
         bitbake("{} {}:do_addto_recipe_sysroot".format(image, binutils))
diff --git a/meta/recipes-core/systemd/systemd_254.4.bb b/meta/recipes-core/systemd/systemd_254.4.bb
index 4d68a3266a..0c12926bef 100644
--- a/meta/recipes-core/systemd/systemd_254.4.bb
+++ b/meta/recipes-core/systemd/systemd_254.4.bb
@@ -67,6 +67,7 @@  PAM_PLUGINS = " \
 
 PACKAGECONFIG ??= " \
     ${@bb.utils.filter('DISTRO_FEATURES', 'acl audit efi ldconfig pam selinux smack usrmerge polkit seccomp', d)} \
+    ${@bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', 'coredump elfutils', '', d)} \
     ${@bb.utils.contains('DISTRO_FEATURES', 'wifi', 'rfkill', '', d)} \
     ${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'xkbcommon', '', d)} \
     ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', '', 'link-udev-shared', d)} \
diff --git a/meta/recipes-devtools/elfutils/elfutils_0.189.bb b/meta/recipes-devtools/elfutils/elfutils_0.189.bb
index d8bf82b022..d69828131e 100644
--- a/meta/recipes-devtools/elfutils/elfutils_0.189.bb
+++ b/meta/recipes-devtools/elfutils/elfutils_0.189.bb
@@ -39,7 +39,9 @@  BUILD_CFLAGS += "-Wno-error=stringop-overflow"
 DEPENDS_BZIP2 = "bzip2-replacement-native"
 DEPENDS_BZIP2:class-target = "bzip2"
 
-PACKAGECONFIG ??= "${@bb.utils.contains('DISTRO_FEATURES', 'debuginfod', 'debuginfod libdebuginfod', '', d)}"
+PACKAGECONFIG ??= "${@bb.utils.contains('DISTRO_FEATURES', 'debuginfod', 'debuginfod libdebuginfod', '', d)} \
+                   ${@bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', 'xz', '', d)} \
+                  "
 PACKAGECONFIG[bzip2] = "--with-bzlib,--without-bzlib,${DEPENDS_BZIP2}"
 PACKAGECONFIG[xz] = "--with-lzma,--without-lzma,xz"
 PACKAGECONFIG[zstd] = "--with-zstd,--without-zstd,zstd"
diff --git a/meta/recipes-devtools/gdb/gdb-common.inc b/meta/recipes-devtools/gdb/gdb-common.inc
index 3349719a6b..48dbb91463 100644
--- a/meta/recipes-devtools/gdb/gdb-common.inc
+++ b/meta/recipes-devtools/gdb/gdb-common.inc
@@ -30,7 +30,9 @@  EXTRA_OECONF = "--disable-gdbtk --disable-x --disable-werror \
                 --with-libgmp-prefix=${STAGING_EXECPREFIXDIR} \
 "
 
-PACKAGECONFIG ??= "readline ${@bb.utils.filter('DISTRO_FEATURES', 'debuginfod', d)} python"
+PACKAGECONFIG ??= "readline ${@bb.utils.filter('DISTRO_FEATURES', 'debuginfod', d)} python \
+                   ${@bb.utils.contains('DISTRO_FEATURES', 'minidebuginfo', 'xz', '', d)} \
+                  "
 # Use --without-system-readline to compile with readline 5.
 PACKAGECONFIG[readline] = "--with-system-readline,--without-system-readline,readline"
 PACKAGECONFIG[python] = "--with-python=${WORKDIR}/python,--without-python,python3,python3-codecs"