debugedit didn't have any direct tests, it was only tested indirectly
through some other debuginfo testcases.  So add some testcases that
just test debugedit functionality directly.

The tests create different kinds of ELF files (object files, partially
linked files and executables) and run debugedit path replacements on
them, checking that the resulting .debug_str, .debug_info and .debug_line
sections look sane.

Testcases verified against various different gcc and binutils versions.
gcc 4.8 and gcc 6 generate slightly different .debuginfo

Also add debugedit --version. Which makes it easy to see we are
testing the correct version/install of debugedit in rpmtests.log.

Adjust autotest paths to include rpmlibexecdir, where debuginfo
is installed.  Note that rpmlibexecdir != libexecdir (see rpm.am).
---
 tests/Makefile.am           |   8 +-
 tests/atlocal.in            |   2 +-
 tests/data/SOURCES/bar.c    |   9 ++
 tests/data/SOURCES/baz.c    |  10 ++
 tests/data/SOURCES/foo.c    |   7 +
 tests/data/SOURCES/foobar.h |   6 +
 tests/debugedit.at          | 322 ++++++++++++++++++++++++++++++++++++++++++++
 tests/rpmtests.at           |   1 +
 tools/debugedit.c           |  10 ++
 9 files changed, 373 insertions(+), 2 deletions(-)
 create mode 100644 tests/data/SOURCES/bar.c
 create mode 100644 tests/data/SOURCES/baz.c
 create mode 100644 tests/data/SOURCES/foo.c
 create mode 100644 tests/data/SOURCES/foobar.h
 create mode 100644 tests/debugedit.at

diff --git a/tests/Makefile.am b/tests/Makefile.am
index abad3f4..6f909d7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -18,6 +18,7 @@ TESTSUITE_AT += rpmverify.at
 TESTSUITE_AT += rpmdb.at
 TESTSUITE_AT += rpmbuild.at
 TESTSUITE_AT += rpmbuildid.at
+TESTSUITE_AT += debugedit.at
 TESTSUITE_AT += rpmi.at
 TESTSUITE_AT += rpmvercmp.at
 TESTSUITE_AT += rpmdeps.at
@@ -99,6 +100,10 @@ EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.pub
 EXTRA_DIST += data/keys/rpm.org-rsa-2048-test.secret
 EXTRA_DIST += data/macros.testfile
 EXTRA_DIST += data/macros.debug
+EXTRA_DIST += data/SOURCES/foo.c
+EXTRA_DIST += data/SOURCES/bar.c
+EXTRA_DIST += data/SOURCES/baz.c
+EXTRA_DIST += data/SOURCES/foobar.h
 
 .PHONY: populate_testing
 
@@ -129,6 +134,7 @@ atlocal:    atlocal.in Makefile
          -e "s,[@]usrbindir[@],$(bindir)," \
          -e "s,[@]usrlibdir[@],$(libdir)," \
          -e "s,[@]execprefix[@],$(exec_prefix)," \
+         -e "s,[@]usrlibexecdir[@],$(rpmlibexecdir),g" \
          -e "s,[@]RPMCONFIGDIR[@],$(rpmconfigdir)," \
          -e "s,[@]PYTHON[@],$(PYTHON)," \
        < $(srcdir)/atlocal.in > atlocal
@@ -170,7 +176,7 @@ check-local:
 endif !HAVE_FAKECHROOT
 
 installcheck-local: $(check_DATA) populate_testing
-       $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS)
+       $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir):$(rpmlibexecdir)' 
$(TESTSUITEFLAGS)
        HOME=$(abs_builddir)/testing $(KILLAGENT) ||:
 
 clean-local:
diff --git a/tests/atlocal.in b/tests/atlocal.in
index fcbf783..0974693 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -1,6 +1,6 @@
 LD_LIBRARY_PATH="${abs_builddir}/testing@usrlibdir@"
 export LD_LIBRARY_PATH
-PATH="${abs_builddir}/testing@rpmbindir@:${abs_builddir}/testing@usrbindir@:$PATH"
+PATH="${abs_builddir}/testing@rpmbindir@:${abs_builddir}/testing@usrbindir@:${abs_builddir}/testing@usrlibexecdir@:$PATH"
 export PATH
 
 PYTHON=@PYTHON@
diff --git a/tests/data/SOURCES/bar.c b/tests/data/SOURCES/bar.c
new file mode 100644
index 0000000..6d67469
--- /dev/null
+++ b/tests/data/SOURCES/bar.c
@@ -0,0 +1,9 @@
+#include "foobar.h"
+
+int number = NUMBER;
+
+int
+bar (int n)
+{
+  return n - NUMBER;
+}
diff --git a/tests/data/SOURCES/baz.c b/tests/data/SOURCES/baz.c
new file mode 100644
index 0000000..4723022
--- /dev/null
+++ b/tests/data/SOURCES/baz.c
@@ -0,0 +1,10 @@
+#include "foobar.h"
+
+int
+main ()
+{
+  int res;
+  res = foo ();
+  res = bar (res);
+  return res + number - NUMBER;
+}
diff --git a/tests/data/SOURCES/foo.c b/tests/data/SOURCES/foo.c
new file mode 100644
index 0000000..57906a2
--- /dev/null
+++ b/tests/data/SOURCES/foo.c
@@ -0,0 +1,7 @@
+#include "foobar.h"
+
+int
+foo ()
+{
+  return number;
+}
diff --git a/tests/data/SOURCES/foobar.h b/tests/data/SOURCES/foobar.h
new file mode 100644
index 0000000..6db49a8
--- /dev/null
+++ b/tests/data/SOURCES/foobar.h
@@ -0,0 +1,6 @@
+#define NUMBER 42
+
+extern int number;
+
+extern int foo (void);
+extern int bar (int);
diff --git a/tests/debugedit.at b/tests/debugedit.at
new file mode 100644
index 0000000..8b724d3
--- /dev/null
+++ b/tests/debugedit.at
@@ -0,0 +1,322 @@
+# debugedit.at: Tests for the debugedit tool
+#
+# Copyright (C) 2019 Mark J. Wielaard <m...@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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see see <http://www.gnu.org/licenses/>.
+
+# Tests for the tools/debugedit program.
+AT_BANNER([RPM debugedit])
+
+# Show which debugedit binary we are testing.
+AT_TESTED([debugedit])
+
+# Helper to create some test binaries.
+m4_define([RPM_DEBUGEDIT_SETUP],[[
+# Create some test binaries. Create and build them in different subdirs
+# to make sure they produce different relative/absolute paths.
+
+mkdir subdir_foo
+cp "${abs_srcdir}"/data/SOURCES/foo.c subdir_foo
+mkdir subdir_bar
+cp "${abs_srcdir}"/data/SOURCES/bar.c subdir_bar
+mkdir subdir_headers
+cp "${abs_srcdir}"/data/SOURCES/foobar.h subdir_headers
+cp "${abs_srcdir}"/data/SOURCES/baz.c .
+
+# First three object files (foo.o subdir_bar/bar.o and baz.o)
+gcc -g -Isubdir_headers -c subdir_foo/foo.c
+cd subdir_bar
+gcc -g -I../subdir_headers -c bar.c
+cd ..
+gcc -g -I$(pwd)/subdir_headers -c $(pwd)/baz.c
+
+# Then a partially linked object file (somewhat like a kernel module).
+# This will still have relocations between the debug sections.
+ld -r -o foobarbaz.part.o foo.o subdir_bar/bar.o baz.o
+
+# Create an executable. Relocations between debug sections will
+# have been resolved.
+gcc -g -o foobarbaz.exe foo.o subdir_bar/bar.o baz.o
+]])
+
+# ===
+# Check debugedit --help doesn't crash and burn.
+# ===
+AT_SETUP([debugedit help])
+AT_KEYWORDS([debuginfo] [debugedit])
+AT_CHECK([debugedit --help],[0],[ignore],[ignore])
+AT_CLEANUP
+
+# ===
+# Make sure that an executable still runs after debugedit munged it.
+# ===
+AT_SETUP([debugedit executable])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+AT_CHECK([[./foobarbaz.exe]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.exe]])
+AT_CHECK([[./foobarbaz.exe]])
+
+AT_CLEANUP
+
+# ===
+# debugedit should at least replace the .debug_str directory paths
+# in the objects.
+# ===
+AT_SETUP([debugedit .debug_str objects])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+# Capture strings that start with the testdir (pwd) directory path
+# (and replace that textually with /foo/bar/baz)
+readelf -p.debug_str foo.o subdir_bar/bar.o baz.o | cut -c13- \
+        | grep ^$(pwd) | sort \
+        | sed -e "s@$(pwd)@/foo/bar/baz@" > expout
+
+# Make sure there is at least some output
+expout_lines=$(wc --lines expout | cut -f1 -d\ )
+if test $expout_lines -lt 3; then
+  echo "Expecting at least 3 debug strings starting with ${testdir}" >> expout
+fi
+
+# Check the replaced strings are all there.
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foo.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./subdir_bar/bar.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./baz.o]])
+AT_CHECK([[
+readelf -p.debug_str foo.o subdir_bar/bar.o baz.o | cut -c13- \
+        | grep ^/foo/bar/baz | sort
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# debugedit should at least replace the .debug_str directory paths
+# also in partially linked files.
+# ===
+AT_SETUP([debugedit .debug_str partial])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+# Capture strings that start with the testdir (pwd) directory path
+# (and replace that textually with /foo/bar/baz)
+# Note that partially linked files, might have multiple duplicate
+# strings, but debugedit will merge them. So use sort -u.
+readelf -p.debug_str ./foobarbaz.part.o | cut -c13- \
+        | grep ^$(pwd) | sort -u \
+        | sed -e "s@$(pwd)@/foo/bar/baz@" > expout
+
+# Make sure there is at least some output
+expout_lines=$(wc --lines expout | cut -f1 -d\ )
+if test $expout_lines -lt 3; then
+  echo "Expecting at least 3 debug strings starting with ${testdir}" >> expout
+fi
+
+# Check the replaced strings are all there.
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.part.o]])
+AT_CHECK([[
+readelf -p.debug_str ./foobarbaz.part.o | cut -c13- \
+        | grep ^/foo/bar/baz | sort
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# debugedit should at least replace the .debug_str directory paths
+# and in the executable.
+# ===
+AT_SETUP([debugedit .debug_str exe])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+# Capture strings that start with the testdir (pwd) directory path
+# (and replace that textually with /foo/bar/baz)
+readelf -p.debug_str foobarbaz.exe | cut -c13- \
+        | grep ^$(pwd) | sort \
+        | sed -e "s@$(pwd)@/foo/bar/baz@" > expout
+
+# Make sure there is at least some output
+# The linker will have merged unique strings, so no need for sort -u.
+expout_lines=$(wc --lines expout | cut -f1 -d\ )
+if test $expout_lines -lt 3; then
+  echo "Expecting at least 3 debug strings starting with ${testdir}" >> expout
+fi
+
+# Check the replaced strings are all there.
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.exe]])
+AT_CHECK([[
+readelf -p.debug_str foobarbaz.exe | cut -c13- \
+        | grep ^/foo/bar/baz | sort
+]],[0],[expout])
+
+AT_CLEANUP
+
+# For .debug_info we expect the following DW_AT_name and DW_AT_comp_dir
+# strings for the DW_TAG_compile_unit:
+# - foo.o
+#   DW_AT_name: subdir_foo/foo.c
+#   DW_AT_comp_dir: /foo/baz/baz
+# - bar.o
+#   DW_AT_name: bar.c
+#   DW_AT_comp_dir: /foo/bar/baz/subdir_bar
+# - baz.o
+#   DW_AT_name: /foo/bar/baz/baz.c
+#   DW_AT_comp_dir: /foo/baz/baz
+#
+# Older gcc (before 7) don't emit the DW_AT_comp_dir for baz.o.
+# But because it is similar to the comp_dir of foo.o, just sort -u.
+
+# ===
+# Make sure DW_AT_name and DW_AT_comp_dir strings are replaced
+# in objects.
+# ===
+AT_SETUP([debugedit .debug_info objects])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+AT_DATA([expout],
+[/foo/bar/baz
+/foo/bar/baz/baz.c
+/foo/bar/baz/subdir_bar
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foo.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./subdir_bar/bar.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./baz.o]])
+AT_CHECK([[
+readelf --debug-dump=info foo.o subdir_bar/bar.o baz.o \
+        | grep -E 'DW_AT_(name|comp_dir)' \
+        | rev | cut -d: -f1 | rev | cut -c2- | grep ^/foo/bar/baz | sort -u
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# Make sure DW_AT_name and DW_AT_comp_dir strings are replaced
+# in partial linked object.
+# ===
+AT_SETUP([debugedit .debug_info partial])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+AT_DATA([expout],
+[/foo/bar/baz
+/foo/bar/baz/baz.c
+/foo/bar/baz/subdir_bar
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.part.o]])
+AT_CHECK([[
+readelf --debug-dump=info ./foobarbaz.part.o \
+        | grep -E 'DW_AT_(name|comp_dir)' \
+        | rev | cut -d: -f1 | rev | cut -c2- | grep ^/foo/bar/baz | sort -u
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# Make sure DW_AT_name and DW_AT_comp_dir strings are replaced
+# in executable.
+# ===
+AT_SETUP([debugedit .debug_info exe])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+AT_DATA([expout],
+[/foo/bar/baz
+/foo/bar/baz/baz.c
+/foo/bar/baz/subdir_bar
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.exe]])
+AT_CHECK([[
+readelf --debug-dump=info ./foobarbaz.exe | grep -E 'DW_AT_(name|comp_dir)' \
+        | rev | cut -d: -f1 | rev | cut -c2- | grep ^/foo/bar/baz | sort -u
+]],[0],[expout])
+
+AT_CLEANUP
+
+# foo.o and bar.o are build with relative paths and so will use the
+# comp_dir (from .debug_info). But bar.o is build from sources with
+# an absolute path, so the .debug_line Directory Table should contain
+# /foo/bar/baz and /foo/bar/baz/subdir_headers.
+
+# ===
+# Make sure .debug_line Directory Table entries are replaced
+# in objects.
+# ===
+AT_SETUP([debugedit .debug_line objects])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+AT_DATA([expout],
+[/foo/bar/baz
+/foo/bar/baz/subdir_headers
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foo.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./subdir_bar/bar.o]])
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./baz.o]])
+AT_CHECK([[
+readelf --debug-dump=line foo.o subdir_bar/bar.o baz.o \
+        | grep -A3 "The Directory Table" | grep "^  [123]" \
+       | grep /foo/ | cut -c5- | sort
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# Make sure .debug_line Directory Table entries are replaced
+# in partial linked object.
+# ===
+AT_SETUP([debugedit .debug_line partial])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+AT_DATA([expout],
+[/foo/bar/baz
+/foo/bar/baz/subdir_headers
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.part.o]])
+AT_CHECK([[
+readelf --debug-dump=line ./foobarbaz.part.o \
+        | grep -A3 "The Directory Table" | grep "^  [123]" \
+       | grep /foo/ | cut -c5- | sort
+]],[0],[expout])
+
+AT_CLEANUP
+
+# ===
+# Make sure .debug_line Directory Table entries are replaced
+# in executable.
+# ===
+AT_SETUP([debugedit .debug_line exe])
+AT_KEYWORDS([debuginfo] [debugedit])
+RPM_DEBUGEDIT_SETUP
+
+AT_DATA([expout],
+[/foo/bar/baz
+/foo/bar/baz/subdir_headers
+])
+
+AT_CHECK([[debugedit -b $(pwd) -d /foo/bar/baz ./foobarbaz.exe]])
+AT_CHECK([[
+readelf --debug-dump=line ./foobarbaz.exe \
+        | grep -A3 "The Directory Table" | grep "^  [123]" \
+       | grep /foo/ | cut -c5- | sort
+]],[0],[expout])
+
+AT_CLEANUP
diff --git a/tests/rpmtests.at b/tests/rpmtests.at
index a1adab8..48b86bd 100644
--- a/tests/rpmtests.at
+++ b/tests/rpmtests.at
@@ -14,6 +14,7 @@ m4_include([rpmi.at])
 m4_include([rpmorder.at])
 m4_include([rpmbuild.at])
 m4_include([rpmbuildid.at])
+m4_include([debugedit.at])
 m4_include([rpmscript.at])
 m4_include([rpmdeps.at])
 m4_include([rpmconflict.at])
diff --git a/tools/debugedit.c b/tools/debugedit.c
index 84568dd..4be85b9 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -88,6 +88,8 @@ int do_build_id = 0;
 int no_recompute_build_id = 0;
 char *build_id_seed = NULL;
 
+int show_version = 0;
+
 /* We go over the debug sections in two phases. In phase zero we keep
    track of any needed changes and collect strings, indexes and
    sizes. In phase one we do the actual replacements updating the
@@ -2291,6 +2293,8 @@ static struct poptOption optionsTable[] = {
       "if recomputing the build ID note use this string as hash seed", NULL },
     { "no-recompute-build-id",  'n', POPT_ARG_NONE, &no_recompute_build_id, 0,
       "do not recompute build ID note even when -i or -s are given", NULL },
+    { "version", '\0', POPT_ARG_NONE, &show_version, 0,
+      "print the debugedit version", NULL },
       POPT_AUTOHELP
     { NULL, 0, 0, NULL, 0, NULL, NULL }
 };
@@ -2527,6 +2531,12 @@ main (int argc, char *argv[])
       exit (1);
     }
 
+  if (show_version)
+    {
+      printf("RPM debugedit %s\n", VERSION);
+      exit(EXIT_SUCCESS);
+    }
+
   args = poptGetArgs (optCon);
   if (args == NULL || args[0] == NULL || args[1] != NULL)
     {
-- 
1.8.3.1

_______________________________________________
Rpm-maint mailing list
Rpm-maint@lists.rpm.org
http://lists.rpm.org/mailman/listinfo/rpm-maint

Reply via email to