[PATCH] find-debuginfo: Add --check-elf[-strict] to invoke eu-elflint
Mark Wielaard
mark@klomp.org
Sun Jan 25 21:41:53 GMT 2026
To make sure the ELF and AR file processed by and created by
find-debuginfo are valid introduce a --check-elf[-strict] option. The
--check-elf and --check-elf-strict flags will run eu-elflint --gnu on
the ELF and AR files before and after processing the files. Including
on the generated separate .debug files. When --check-elf-strict is
given then if eu-elflint reports any errors find-debuginfo will exit
with a failure status. With just --check-elf given any eu-elflint
output will be logged but not change the exit status.
Add a couple of testcases using --check-elf-strict including minidata,
gdb index, dwz creation and an AR file.
* configure.ac: Add check for eu-elflint.
* scripts/find-debuginfo.in: Add new flags in usage and help.
(check_elf, check_elf_strict, elflint_opts, check_elf_msg):
New vars. Process --check-elf, --check-elf-struct opts.
(do_check_elf): New function.
(do_ar_file): Call do_check_elf before/after AR file processing.
Propagate return value to caller.
(do_file): Check and propagate return value for
do_ar_file. Call do_check_elf before and after processing ELF
file. Also check debug file.
* tests/find-debuginfo.at (FIND_DEBUGINFO_PKG_BUILD_SETUP):
Create .o object files.
Add tests for --check-elf-strict plus debugdata, gdb-index and
dwz. Create ar file from object files and check.
https://sourceware.org/bugzilla/show_bug.cgi?id=33827
---
configure.ac | 7 ++-
scripts/find-debuginfo.in | 67 ++++++++++++++++++++-
tests/find-debuginfo.at | 121 ++++++++++++++++++++++++++++++++++++--
3 files changed, 187 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index ad73fe7f0d9b..a0cbb5445803 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
-# Copyright (C) 2021, 2024, 2025 Mark J. Wielaard <mark@klomp.org>
+# Copyright (C) 2021, 2024, 2025, 2026 Mark J. Wielaard <mark@klomp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -70,6 +70,11 @@ if test x$HAS_GDB_ADD_INDEX = xno; then
AC_MSG_ERROR([gdb-add-index needed by find-debuginfo])
fi
+AC_CHECK_PROG([HAS_EU_ELFLINT], [eu-elflint], [yes], [no])
+if test x$HAS_HAS_EU_ELFLINT = xno; then
+ AC_MSG_ERROR([eu-elflint needed by find-debuginfo (--check-elf)])
+fi
+
# Whether dwz support -j.
# Make sure to compile something with -g.
# Run dwz on it with -j1.
diff --git a/scripts/find-debuginfo.in b/scripts/find-debuginfo.in
index b44f25ffef49..8590c42650d1 100755
--- a/scripts/find-debuginfo.in
+++ b/scripts/find-debuginfo.in
@@ -6,6 +6,7 @@
# Copyright (C) 2002-2021 rpm and debugedit contributors
# Copyright (C) 2025 Red Hat Inc.
+# Copyright (C) 2026 Mark J. Wielaard <mark@klomp.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -41,6 +42,7 @@ Options:
[--unique-debug-suffix SUFFIX]
[--unique-debug-src-base BASE]
[[-l filelist]... [-p 'pattern'] -o debuginfo.list]
+[--check-elf] [--check-elf-strict]
[builddir]
The -g flag says to use strip -g instead of full strip on DSOs or EXEs.
@@ -110,6 +112,14 @@ The -q or --quiet flag silences all non-error output from the script.
The -v or --verbose flag add more output for all files processed.
When neither -q or -v is given then only output for each pass is given.
+The --check-elf and --check-elf-strict flags will run eu-elflint --gnu
+on the ELF and AR files before and after processing the
+files. Including on the generated separate .debug files. When
+--check-elf-strict is given then if eu-elflint reports any errors
+find-debuginfo will exit with a failure status. With just --check-elf
+given any eu-elflint output will be logged but not change the exit
+status.
+
All file names in switches are relative to builddir ('.' if not given).
EOF
}
@@ -152,6 +162,12 @@ strict=false
# Do not recompute build IDs.
no_recompute_build_id=false
+# Whether to run eu-elflint on all files
+check_elf=false
+
+# Whether eu-elflint reporting an issue should result in a fatal exit
+check_elf_strict=false
+
# DWZ parameters.
run_dwz=false
dwz_low_mem_die_limit=
@@ -189,6 +205,9 @@ else
process_ar=false
fi
+# which flags to use for eu-elflint, always use --gnu
+# Others set below based on verbose/quiet
+elflint_opts="--gnu"
BUILDDIR=.
OUTDIR=
@@ -291,6 +310,13 @@ while [ $# -gt 0 ]; do
--no-ar-files)
process_ar=false
;;
+ --check-elf)
+ check_elf=true
+ ;;
+ --check-elf-strict)
+ check_elf=true
+ check_elf_strict=true
+ ;;
-q|--quiet)
quiet=true
verbose=false
@@ -341,6 +367,8 @@ if [ "$strip_g" = "true" ] && [ "$strip_glibs" = "true" ]; then
exit 2
fi
+$verbose || elflint_opts="$elflint_opts --quiet"
+
$quiet || echo "find-debuginfo: starting" 2>&1
[ -z "$OUTDIR" ] && OUTDIR=$BUILDDIR
@@ -471,6 +499,10 @@ set -o pipefail
strict_error=ERROR
$strict || strict_error=WARNING
+# Setup for do_check_elf
+check_elf_msg=ERROR
+$check_elf_strict || check_elf_msg=WARNING
+
temp=$(mktemp -d ${TMPDIR:-/tmp}/find-debuginfo.XXXXXX)
trap 'rm -rf "$temp"' EXIT
@@ -503,6 +535,26 @@ while read nlinks inum f; do
echo "$nlinks $inum $f" >>"$temp/primary"
done
+# Check ELF or AR file with eu-elflint if --elf-check is given.
+# Returns 1 if --elf-check-strict is given and eu-elflint reports issues.
+# Otherwise returns 0.
+do_check_elf()
+{
+ local msg="$1"
+ local file="$2"
+ local debug_opt="$3"
+ local issue
+
+ if [ "$check_elf" = "true" ]; then
+ $verbose && echo "$msg $file"
+ eu-elflint $elflint_opts $debug_opt "$file"
+ if [ $? -ne 0 ]; then
+ echo "$check_elf_msg: eu-elflint found issues in $file"
+ $check_elf_strict && return 1
+ fi
+ fi
+ return 0
+}
# Handle ELF archives
do_ar_file()
@@ -520,7 +572,9 @@ do_ar_file()
fi
$verbose && echo "processing debug info in $f"
-
+
+ do_check_elf "pre-check AR file" "$f" "" || return 1
+
# Extract members from archive, one at a time. There may be
# duplicate names, so we can't just extract the entire archive in
# one go (overwriting each other). Instead, we pick off member
@@ -603,6 +657,8 @@ do_ar_file()
$verbose && echo found $(tr -dc '\0' < "$SOURCEFILE" | wc -c) source files
+ do_check_elf "check AR file" "$f" "" || return 1
+
# NB: no need to strip or dwz-compress or gdbindex or
# ELFBINSFILE-collect objects / archives. These operations only
# make sense on the final binaries that the static archives are
@@ -641,11 +697,13 @@ do_file()
$verbose && classify_opts="$classify_opts --verbose"
$quiet && classify_opts="$classify_opts --quiet"
if debugedit-classify-ar $classify_opts "$f"; then
- do_ar_file "$1" "$2" "$3"
+ do_ar_file "$1" "$2" "$3" || return 1
fi
- return
+ return 0;
fi
+ do_check_elf "pre-check ELF file" "$f" || return 1
+
$verbose && echo "extracting debug info from $f"
# See also cpio SOURCEFILE copy. Directories must match up.
debug_base_name="$RPM_BUILD_DIR"
@@ -751,6 +809,9 @@ do_file()
echo "./${f#$RPM_BUILD_ROOT}" >> "$ELFBINSFILE"
+ do_check_elf "check ELF file" "$f" "" || return 1
+ do_check_elf "check debug file" "$debugfn" "--debug" || return 1
+
# If this file has multiple links, make the corresponding .debug files
# all links to one file too.
if [ $nlinks -gt 1 ]; then
diff --git a/tests/find-debuginfo.at b/tests/find-debuginfo.at
index 0aa07525cefd..ba4beabffc09 100644
--- a/tests/find-debuginfo.at
+++ b/tests/find-debuginfo.at
@@ -1,7 +1,7 @@
# find-debuginfo.at: Tests for the find-debuginfo script
#
# Copyright (C) 2025 Red Hat Inc.
-# Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
+# Copyright (C) 2025, 2026 Mark J. Wielaard <mark@klomp.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -91,11 +91,15 @@ cp "${abs_srcdir}"/data/SOURCES/bar.c subdir_build
cp "${abs_srcdir}"/data/SOURCES/foobar.h subdir_build
cp "${abs_srcdir}"/data/SOURCES/baz.c subdir_build
cd subdir_build
+# Create .o files to pack into an .a later
+$CC $CFLAGS -g3 -I. -c foo.c
+$CC $CFLAGS -g3 -I. -c bar.c
+$CC $CFLAGS -g3 -I. -c baz.c
# Three almost identical binaries
# so dwz has something to put into the alt file
-$CC $CFLAGS -Wl,--build-id -g3 -I. -o foo foo.c bar.c baz.c
-$CC $CFLAGS -Wl,--build-id -g3 -I. -o bar bar.c baz.c foo.c
-$CC $CFLAGS -Wl,--build-id -g3 -I. -o baz baz.c foo.c bar.c
+$CC $CFLAGS -Wl,--build-id -g3 -I. -o foo foo.o bar.o baz.o
+$CC $CFLAGS -Wl,--build-id -g3 -I. -o bar bar.o baz.o foo.o
+$CC $CFLAGS -Wl,--build-id -g3 -I. -o baz baz.o foo.o bar.o
cd ..
]])
@@ -454,3 +458,112 @@ AT_CHECK([(echo allfiles.list; echo "FIND_DEBUGINFO_OUTPUT_FILES") |
sort > expout], [0], [], [])
AT_CHECK([ls output | sort], [0], [expout], [])
AT_CLEANUP
+
+# Run find-debuginfo on a small build and check elf file
+AT_SETUP([find-debuginfo check-elf])
+AT_KEYWORDS([find-debuginfo] [check-elf])
+FIND_DEBUGINFO_PKG_BUILD_SETUP
+# We need to set some environment variables for running find-debuginfo
+# normally set by rpmbuild.
+AT_CHECK([env RPM_BUILD_DIR=${PWD} \
+ RPM_BUILD_ROOT=${PWD} \
+ RPM_PACKAGE_NAME=pkg \
+ RPM_PACKAGE_VERSION=ver \
+ RPM_PACKAGE_RELEASE=rel \
+ RPM_ARCH=arch \
+ find-debuginfo --check-elf-strict --verbose ${PWD}/subdir_build],
+ [0], [stdout], [])
+AT_CHECK([grep "No errors" stdout], [0], [ignore], [])
+AT_CLEANUP
+
+# Run find-debuginfo on a small build and check elf file
+AT_SETUP([find-debuginfo check-elf debugdata])
+AT_KEYWORDS([find-debuginfo] [check-elf] [debugdata])
+FIND_DEBUGINFO_PKG_BUILD_SETUP
+# We need to set some environment variables for running find-debuginfo
+# normally set by rpmbuild.
+#
+# generate .gnu_debugdata (-m) for binaries in subdir_build.
+AT_CHECK([env RPM_BUILD_DIR=${PWD} \
+ RPM_BUILD_ROOT=${PWD} \
+ RPM_PACKAGE_NAME=pkg \
+ RPM_PACKAGE_VERSION=ver \
+ RPM_PACKAGE_RELEASE=rel \
+ RPM_ARCH=arch \
+ find-debuginfo -m --check-elf-strict --verbose ${PWD}/subdir_build],
+ [0], [stdout], [])
+AT_CHECK([grep "No errors" stdout], [0], [ignore], [])
+AT_CLEANUP
+
+# Run find-debuginfo on a small build and check elf file
+AT_SETUP([find-debuginfo check-elf debugdata gdb-index])
+AT_KEYWORDS([find-debuginfo] [check-elf] [debugdata] [gdb-index])
+# Too new gdb with too old gdb
+AT_SKIP_IF([test "$GDB_ADD_INDEX_CHECKS_OK" = "no"])
+FIND_DEBUGINFO_PKG_BUILD_SETUP
+# We need to set some environment variables for running find-debuginfo
+# normally set by rpmbuild.
+#
+# generate .gnu_debugdata (-m) and .gdb_index (-i) for binaries in
+# subdir_build.
+AT_CHECK([env RPM_BUILD_DIR=${PWD} \
+ RPM_BUILD_ROOT=${PWD} \
+ RPM_PACKAGE_NAME=pkg \
+ RPM_PACKAGE_VERSION=ver \
+ RPM_PACKAGE_RELEASE=rel \
+ RPM_ARCH=arch \
+ find-debuginfo -m -i --check-elf-strict --verbose ${PWD}/subdir_build],
+ [0], [stdout], [])
+AT_CHECK([grep "No errors" stdout], [0], [ignore], [])
+AT_CLEANUP
+
+# Run find-debuginfo on a small build and check elf file
+AT_SETUP([find-debuginfo check-elf debugdata gdb-index dwz])
+AT_KEYWORDS([find-debuginfo] [check-elf] [debugdata] [gdb-index] [dwz])
+# At the moment dwz doesn't support .debug_addr
+AT_SKIP_IF([test "$DWARF_5_DEBUGADDR" = "yes"])
+# Too new gdb with too old gdb
+AT_SKIP_IF([test "$GDB_ADD_INDEX_CHECKS_OK" = "no"])
+FIND_DEBUGINFO_PKG_BUILD_SETUP
+# We need to set some environment variables for running find-debuginfo
+# normally set by rpmbuild.
+#
+# generate .gnu_debugdata (-m), .gdb_index (-i) and run dwz (--run-dwz)
+# for binaries in subdir_build.
+AT_CHECK([env RPM_BUILD_DIR=${PWD} \
+ RPM_BUILD_ROOT=${PWD} \
+ RPM_PACKAGE_NAME=pkg \
+ RPM_PACKAGE_VERSION=ver \
+ RPM_PACKAGE_RELEASE=rel \
+ RPM_ARCH=arch \
+ find-debuginfo -m -i --run-dwz --check-elf-strict --verbose ${PWD}/subdir_build],
+ [0], [stdout], [])
+AT_CHECK([grep "No errors" stdout], [0], [ignore], [])
+AT_CLEANUP
+
+# Run find-debuginfo on a small build, create an archive and check files
+AT_SETUP([find-debuginfo check-elf ar])
+AT_KEYWORDS([find-debuginfo] [check-elf] [ar])
+# skip if ar too old to support O
+AT_SKIP_IF([ test -z "`ar 2>&1 | grep -F '[O]'`" ])
+FIND_DEBUGINFO_PKG_BUILD_SETUP
+# Create an archive from the object files
+mkdir -p subdir_ar
+AT_CHECK([ar q ./subdir_ar/archive.a $(find subdir_build -name '*.o')],
+ [0], [ignore], [ignore])
+# Make sure eu-elflint --gnu work on the simple input archive.
+# It might not if llvm is used for example.
+AT_SKIP_IF([! eu-elflint --gnu ./subdir_ar/archive.a | grep -q 'No errors'])
+# We need to set some environment variables for running find-debuginfo
+# normally set by rpmbuild.
+AT_CHECK([env RPM_BUILD_DIR=${PWD} \
+ RPM_BUILD_ROOT=${PWD} \
+ RPM_PACKAGE_NAME=pkg \
+ RPM_PACKAGE_VERSION=ver \
+ RPM_PACKAGE_RELEASE=rel \
+ RPM_ARCH=arch \
+ find-debuginfo --check-elf-strict --verbose ${PWD}/subdir_ar],
+ [0], [stdout], [ignore])
+AT_CHECK([grep "check AR file" stdout], [0], [ignore], [])
+AT_CHECK([grep "No errors" stdout], [0], [ignore], [])
+AT_CLEANUP
--
2.52.0
More information about the Debugedit
mailing list