[PATCH] debugedit: Add -p, --preserve-dates
Mark Wielaard
mark@klomp.org
Mon Jun 30 14:26:40 GMT 2025
Hi,
On Mon, 2025-06-23 at 00:33 +0200, Mark Wielaard wrote:
> 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
After implementing it I don't know if it is strictly necessary, but it
seems useful functionality and comes with testcases so we know if we
accidentally break it. But please let me know if you rather not see
this go in.
Thanks,
Mark
> ---
> 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);
More information about the Debugedit
mailing list