From b8b2316b0a5d14333c1e2c1eed42c48551727bb8 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sat, 16 May 2026 19:09:12 +0000 Subject: [PATCH] tools: add a test wrapper that replays crashing tests under gdb meson test --wrapper hook to print a gdb backtrace inline in the test log when a test exits with an actual crash signal (SIGSEGV, SIGABRT, SIGBUS, SIGFPE, SIGILL). Wired into the default add_test_setup() so it runs automatically on every `meson test`. Environmental terminations (SIGTERM/SIGKILL/SIGPIPE/SIGALRM) are passed through without replay, and the original signal is re-raised so the parent's wait() observes WIFSIGNALED rather than a plain exit code. --- .packit.yml | 22 +++++++++++---- meson.build | 1 + tools/test-crash-trace.sh | 56 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) create mode 100755 tools/test-crash-trace.sh diff --git a/.packit.yml b/.packit.yml index 97e1e58855..e0aa839d92 100644 --- a/.packit.yml +++ b/.packit.yml @@ -28,12 +28,24 @@ actions: jobs: - job: copr_build trigger: pull_request + # Install gdb into the buildroot so post-failure hooks can pull backtraces from any cores the + # %check phase leaves behind. targets: - - fedora-rawhide-aarch64 - - fedora-rawhide-i386 - - fedora-rawhide-ppc64le - - fedora-rawhide-s390x - - fedora-rawhide-x86_64 + fedora-rawhide-aarch64: + additional_packages: + - gdb + fedora-rawhide-i386: + additional_packages: + - gdb + fedora-rawhide-ppc64le: + additional_packages: + - gdb + fedora-rawhide-s390x: + additional_packages: + - gdb + fedora-rawhide-x86_64: + additional_packages: + - gdb - job: tests trigger: pull_request diff --git a/meson.build b/meson.build index c76471e1fe..d9c8b84e47 100644 --- a/meson.build +++ b/meson.build @@ -16,6 +16,7 @@ project('systemd', 'c', add_test_setup( 'default', exclude_suites : ['clang-tidy', 'unused-symbols', 'integration-tests'], + exe_wrapper : find_program('tools/test-crash-trace.sh'), is_default : true, ) diff --git a/tools/test-crash-trace.sh b/tools/test-crash-trace.sh new file mode 100755 index 0000000000..d4a8a60f82 --- /dev/null +++ b/tools/test-crash-trace.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# meson test wrapper that replays crashing tests under gdb and prints a +# backtrace, so SIGSEGV/SIGABRT/etc. failures in CI show a stack trace inline +# in the test log instead of just an exit code. +# +# Usage: meson test --wrapper=$PWD/tools/test-crash-trace.sh + +set -euo pipefail + +if [[ $# -eq 0 ]]; then + echo "usage: $0 [args...]" >&2 + exit 2 +fi + +rc=0 +"$@" || rc=$? + +# Replay only on actual crash signals (128 + signal): SIGILL=132, SIGABRT=134, +# SIGBUS=135, SIGFPE=136, SIGSEGV=139. SIGTERM/SIGKILL/SIGPIPE/SIGALRM mean the +# test was killed by the environment (timeout, etc.), not that it crashed — +# replaying those just makes gdb hit the same kill. +case "$rc" in + 132|134|135|136|139) + if command -v gdb >/dev/null 2>&1; then + echo "===== exit $rc — replaying under gdb =====" >&2 + style_args=() + if [[ -t 2 ]]; then + style_args=(--ex 'set style enabled on') + fi + gdb --batch \ + --ex 'set pagination off' \ + ${style_args[@]+"${style_args[@]}"} \ + --ex 'run' \ + --ex 'thread apply all bt full' \ + --args "$@" >&2 || true + else + echo "===== exit $rc — install gdb for a backtrace =====" >&2 + fi + ;; +esac + +# If the child died by signal, re-raise it so the parent's wait() observes +# WIFSIGNALED instead of a plain exit code. Best-effort: SIGKILL can't be +# delivered to ourselves and would have killed us already. +if [[ $rc -gt 128 ]]; then + sig=$((rc - 128)) + trap - "$sig" 2>/dev/null || true + # Suppress the wrapper bash's own core dump from the re-raised crash signal; + # the original test binary already had its chance to dump core on line 18. + ulimit -c 0 + kill -s "$sig" $$ 2>/dev/null || true +fi + +exit "$rc"