[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