[PATCH] debugedit: Add -p, --preserve-dates

Mark Wielaard mark@klomp.org
Sun Jun 22 22:33:38 GMT 2025


When --preserve-dates is given to debugedit it will take the original
st_atim and st_mtim and put them back using utimensat after processing
the file (and setting back the original st_mode).

Use it in find-debuginfo when processing ar archive entries so
timestamps in new archives are the same when put back.

    * tools/debugedit.c (preserve_dates): New bool.
    (optionsTable): Add preserve-dates.
    (optionsChars): Add p.
    (helpText): Add -p|--preserve-dates.
    (main): Handle 'p'. Use utimensat if preserve_dates true.
    * scripts/find-debuginfo.in (do_ar_file): Use debugedit -p.
    * tests/debugedit.at: Add new debugedit preserve timestamps test.
    * tests/find-debuginfo.at: Select the modes, date and entry names
    in the ar and compare them after find-debuginfo processing.

https://sourceware.org/bugzilla/show_bug.cgi?id=33096
---
 scripts/find-debuginfo.in |  4 ++--
 tests/debugedit.at        | 20 +++++++++++++++++++-
 tests/find-debuginfo.at   |  8 +++++---
 tools/debugedit.c         | 25 ++++++++++++++++++++++---
 4 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/scripts/find-debuginfo.in b/scripts/find-debuginfo.in
index 1a4f2a0b64d3..144fd09bfee5 100755
--- a/scripts/find-debuginfo.in
+++ b/scripts/find-debuginfo.in
@@ -543,12 +543,12 @@ do_ar_file()
           if [ $? -ne 0 ]; then
               res=1
           fi
-          # preserve timestamp from original file, though debugedit may lose it, PR33096
+          # preserve timestamp from original file and invoke debugedit with -p
           touch -d "$date" "$tmpdir/$member_dn$member_bn"
 
           if file "$tmpdir/$member_dn$member_bn" |
                   grep -qE 'ELF.*, not stripped'; then
-              debugedit -b "$debug_base_name" -d "$debug_dest_name" \
+              debugedit -p -b "$debug_base_name" -d "$debug_dest_name" \
 		        -l "$SOURCEFILE" "$tmpdir/$member_dn$member_bn"
               if [ $? -ne 0 ]; then
                   res=1
diff --git a/tests/debugedit.at b/tests/debugedit.at
index 21b67a6e4ef7..042da913af6a 100644
--- a/tests/debugedit.at
+++ b/tests/debugedit.at
@@ -1,6 +1,6 @@
 # debugedit.at: Tests for the debugedit tool
 #
-# Copyright (C) 2019, 2024 Mark J. Wielaard <mark@klomp.org>
+# Copyright (C) 2019, 2024, 2025 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
@@ -920,3 +920,21 @@ AT_CHECK([[expr "$bid3" : '[0-9a-f]*']], [0], [ignore])
 AT_CHECK([[test "$bid3" != "$bid2a"]])
 
 AT_CLEANUP
+
+# Preserving time stamps
+AT_SETUP([debugedit preserve timestamps])
+AT_KEYWORDS([debugedit] [timestamp])
+
+# compile a test program and record the timestamps
+echo "int main () { }" > main.c
+$CC $CFLAGS -g -o main main.c
+AT_CHECK([[stat -c "%x %y" main]], [0], [stdout], [])
+mv stdout expout
+
+# process it with debugedit, using -p
+AT_CHECK([[debugedit -p -b $(pwd) -d /foo/bar/baz ./main]])
+
+# check timestamps were preserved
+AT_CHECK([[stat -c "%x %y" main]], [0], [expout], [])
+
+AT_CLEANUP
diff --git a/tests/find-debuginfo.at b/tests/find-debuginfo.at
index 5552ce17fe58..1deb7edc6a60 100644
--- a/tests/find-debuginfo.at
+++ b/tests/find-debuginfo.at
@@ -61,6 +61,8 @@ $AR qP subdir_build/dupes.a subdir_zo?b/dupe.o subdir_club/dupe.o # with P, thes
 # list old .a contents
 AT_CHECK([$AR tPv subdir_build/dupes.a],[0],[stdout],[ignore])
 AT_CHECK([test `wc -l < stdout` -eq 4],[0],[ignore],[ignore])
+# Select just the modes, date and entry names (see check after debugedit below)
+awk '{print $1, $4, $5, $6, $7, $8, $9}' < stdout > expout
 
 # expect original source tree refs
 AT_CHECK([$READELF --debug-dump=line subdir_build/dupes.a | grep `pwd`], [0], [stdout], [ignore])
@@ -69,9 +71,9 @@ AT_CHECK([$READELF --debug-dump=line subdir_build/dupes.a | grep `pwd`], [0], [s
 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 \
                bash -x `type -p find-debuginfo` -S sourcefiles.list -v ${PWD}/subdir_build]], [0], [stdout], [ignore])
 
-# list new .a contents; ar tPv contains timestamps / subdirs, so not a good fit for AT_DATA() here
-AT_CHECK([$AR tPv subdir_build/dupes.a],[0],[stdout],[ignore])
-AT_CHECK([test `wc -l < stdout` -eq 4],[0],[ignore],[ignore])
+# list new .a contents; expout generated from original (see above)
+# Only check modes, timestamp and archive entry names
+AT_CHECK([$AR tPv subdir_build/dupes.a | awk '{print $1, $4, $5, $6, $7, $8, $9}'],[0],[expout],[ignore])
 
 # expect non-empty source file list
 AT_CHECK([grep . ${PWD}/subdir_build/sourcefiles.list | tr '\0' '\n'], [0], [stdout], [ignore])
diff --git a/tools/debugedit.c b/tools/debugedit.c
index fcf8f7d6564b..03daae10ed7c 100644
--- a/tools/debugedit.c
+++ b/tools/debugedit.c
@@ -1,5 +1,5 @@
 /* Copyright (C) 2001-2003, 2005, 2007, 2009-2011, 2016, 2017 Red Hat, Inc.
-   Copyright (C) 2022, 2023, 2024 Mark J. Wielaard <mark@klomp.org>
+   Copyright (C) 2022, 2023, 2024, 2025 Mark J. Wielaard <mark@klomp.org>
    Written by Alexander Larsson <alexl@redhat.com>, 2002
    Based on code by Jakub Jelinek <jakub@redhat.com>, 2001.
    String/Line table rewriting by Mark Wielaard <mjw@redhat.com>, 2017.
@@ -96,6 +96,7 @@ char *list_file = NULL;
 int list_file_fd = -1;
 int do_build_id = 0;
 int no_recompute_build_id = 0;
+bool preserve_dates = false;
 char *build_id_seed = NULL;
 
 int show_version = 0;
@@ -3399,13 +3400,14 @@ static struct option optionsTable[] =
     { "build-id", no_argument, 0, 'i' },
     { "build-id-seed", required_argument, 0, 's' },
     { "no-recompute-build-id", no_argument, 0, 'n' },
+    { "preserve-dates", no_argument, 0, 'p' },
     { "version", no_argument, 0, 'V' },
     { "help", no_argument, 0, '?' },
     { "usage", no_argument, 0, 'u' },
     { NULL, 0, 0, 0 }
   };
 
-static const char *optionsChars = "b:d:l:is:nV?u";
+static const char *optionsChars = "b:d:l:is:npV?u";
 
 static const char *helpText =
   "Usage: %s [OPTION...] FILE\n"
@@ -3419,6 +3421,7 @@ static const char *helpText =
   "                                  this string as hash seed\n"
   "  -n, --no-recompute-build-id     do not recompute build ID note even\n"
   "                                  when -i or -s are given\n"
+  "  -p, --preserve-dates            Preserve modified/access timestamps\n"
   "\n"
   "Help options:\n"
   "  -?, --help                      Show this help message\n"
@@ -3429,7 +3432,9 @@ static const char *usageText =
   "Usage: %s [-in?] [-b|--base-dir STRING] [-d|--dest-dir STRING]\n"
   "        [-l|--list-file STRING] [-i|--build-id] \n"
   "        [-s|--build-id-seed STRING]\n"
-  "        [-n|--no-recompute-build-id] [-?|--help] [-u|--usage]\n"
+  "        [-n|--no-recompute-build-id]\n"
+  "        [-p|--preserve-dates]\n"
+  "        [-?|--help] [-u|--usage]\n"
   "        [-V|--version] FILE\n";
 
 static void
@@ -3720,6 +3725,10 @@ main (int argc, char *argv[])
 	  no_recompute_build_id = 1;
 	  break;
 
+	case 'p':
+	  preserve_dates = true;
+	  break;
+
 	case 'V':
 	  show_version = 1;
 	  break;
@@ -4046,6 +4055,16 @@ main (int argc, char *argv[])
   if (chmod (file, stat_buf.st_mode) != 0)
     error (0, errno, "Failed to chmod input file '%s' to restore old access rights", file);
 
+  /* Preserve timestamps.  */
+  if (preserve_dates)
+    {
+      struct timespec tv[2];
+      tv[0] = stat_buf.st_atim;
+      tv[1] = stat_buf.st_mtim;
+      if (utimensat (AT_FDCWD, file, tv, 0) != 0)
+	error (0, errno, "Failed to preserve timestamps on '%s'", file);
+    }
+
   free ((char *) dso->filename);
   destroy_strings (&dso->debug_str);
   destroy_strings (&dso->debug_line_str);
-- 
2.49.0



More information about the Debugedit mailing list