elfcmp: Add --ignore-build-id flag.
authorRoland McGrath <roland@redhat.com>
Fri, 11 Feb 2011 18:32:30 +0000 (10:32 -0800)
committerRoland McGrath <roland@redhat.com>
Fri, 11 Feb 2011 18:32:30 +0000 (10:32 -0800)
NEWS
src/ChangeLog
src/elfcmp.c

diff --git a/NEWS b/NEWS
index ca18dc7..989572b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ Various build and warning nits fixed for newest GCC and Autoconf.
 
 libdwfl: Yet another prelink-related fix for another regression.
 
+elfcmp: New flag --ignore-build-id to ignore differing build ID bits.
+
 Version 0.151
 
 libdwfl: Fix for more prelink cases with separate debug file.
index 28d92eb..9ce621f 100644 (file)
@@ -1,3 +1,11 @@
+2011-02-11  Roland McGrath  <roland@redhat.com>
+
+       * elfcmp.c (ignore_build_id): New variable.
+       (options, parse_opt): Grok --ignore-build-id to set it.
+       (main): For SHT_NOTE sections, compare note details rather than raw
+       bytes.  Under --ignore-build-id, don't complain about differing build
+       ID contents if lengths match.
+
 2011-02-08  Roland McGrath  <roland@redhat.com>
 
        * ldscript.y (filename_id_star): Remove unused variable.
index 71a8009..e1aec2b 100644 (file)
@@ -1,5 +1,5 @@
 /* Compare relevant content of two ELF files.
-   Copyright (C) 2005-2010 Red Hat, Inc.
+   Copyright (C) 2005-2011 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2005.
 
@@ -62,6 +62,7 @@ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
 /* Values for the parameters which have no short form.  */
 #define OPT_GAPS               0x100
 #define OPT_HASH_INEXACT       0x101
+#define OPT_IGNORE_BUILD_ID    0x102
 
 /* Definitions of arguments for argp functions.  */
 static const struct argp_option options[] =
@@ -70,6 +71,8 @@ static const struct argp_option options[] =
   { "gaps", OPT_GAPS, "ACTION", 0, N_("Control treatment of gaps in loadable segments [ignore|match] (default: ignore)"), 0 },
   { "hash-inexact", OPT_HASH_INEXACT, NULL, 0,
     N_("Ignore permutation of buckets in SHT_HASH section"), 0 },
+  { "ignore-build-id", OPT_IGNORE_BUILD_ID, NULL, 0,
+    N_("Ignore differences in build ID"), 0 },
   { "quiet", 'q', NULL, 0, N_("Output nothing; yield exit status only"), 0 },
 
   { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
@@ -115,6 +118,9 @@ static bool quiet;
 /* True iff SHT_HASH treatment should be generous.  */
 static bool hash_inexact;
 
+/* True iff build ID notes should be ignored.  */
+static bool ignore_build_id;
+
 static bool hash_content_equivalent (size_t entsize, Elf_Data *, Elf_Data *);
 
 
@@ -385,6 +391,109 @@ main (int argc, char *argv[])
            }
          break;
 
+       case SHT_NOTE:
+         /* Parse the note format and compare the notes themselves.  */
+         {
+           GElf_Nhdr note1;
+           GElf_Nhdr note2;
+
+           size_t off1 = 0;
+           size_t off2 = 0;
+           size_t name_offset;
+           size_t desc_offset;
+           while (off1 < data1->d_size
+                  && (off1 = gelf_getnote (data1, off1, &note1,
+                                           &name_offset, &desc_offset)) > 0)
+             {
+               const char *name1 = data1->d_buf + name_offset;
+               const void *desc1 = data1->d_buf + desc_offset;
+               if (off2 >= data2->d_size)
+                 {
+                   if (! quiet)
+                     error (0, 0, gettext ("\
+%s %s differ: section [%zu] '%s' number of notes"),
+                            fname1, fname2, elf_ndxscn (scn1), sname1);
+                   result = 1;
+                   goto out;
+                 }
+               off2 = gelf_getnote (data2, off2, &note2,
+                                    &name_offset, &desc_offset);
+               if (off2 == 0)
+                 error (2, 0, gettext ("\
+cannot read note section [%zu] '%s' in '%s': %s"),
+                        elf_ndxscn (scn2), sname2, fname2, elf_errmsg (-1));
+               const char *name2 = data2->d_buf + name_offset;
+               const void *desc2 = data2->d_buf + desc_offset;
+
+               if (note1.n_namesz != note2.n_namesz
+                   || memcmp (name1, name2, note1.n_namesz))
+                 {
+                   if (! quiet)
+                     error (0, 0, gettext ("\
+%s %s differ: section [%zu] '%s' note name"),
+                            fname1, fname2, elf_ndxscn (scn1), sname1);
+                   result = 1;
+                   goto out;
+                 }
+               if (note1.n_type != note2.n_type)
+                 {
+                   if (! quiet)
+                     error (0, 0, gettext ("\
+%s %s differ: section [%zu] '%s' note '%s' type"),
+                            fname1, fname2, elf_ndxscn (scn1), sname1, name1);
+                   result = 1;
+                   goto out;
+                 }
+               if (note1.n_descsz != note2.n_descsz
+                   || memcmp (desc1, desc2, note1.n_descsz))
+                 {
+                   if (note1.n_type == NT_GNU_BUILD_ID
+                       && note1.n_namesz == sizeof "GNU"
+                       && !memcmp (name1, "GNU", sizeof "GNU"))
+                     {
+                       if (note1.n_descsz != note2.n_descsz)
+                         {
+                           if (! quiet)
+                             error (0, 0, gettext ("\
+%s %s differ: build ID length"),
+                                    fname1, fname2);
+                           result = 1;
+                           goto out;
+                         }
+                       else if (! ignore_build_id)
+                         {
+                           if (! quiet)
+                             error (0, 0, gettext ("\
+%s %s differ: build ID content"),
+                                    fname1, fname2);
+                           result = 1;
+                           goto out;
+                         }
+                     }
+                   else
+                     {
+                       if (! quiet)
+                         error (0, 0, gettext ("\
+%s %s differ: section [%zu] '%s' note '%s' content"),
+                                fname1, fname2, elf_ndxscn (scn1), sname1,
+                                name1);
+                       result = 1;
+                       goto out;
+                     }
+                 }
+             }
+           if (off2 < data2->d_size)
+             {
+               if (! quiet)
+                 error (0, 0, gettext ("\
+%s %s differ: section [%zu] '%s' number of notes"),
+                        fname1, fname2, elf_ndxscn (scn1), sname1);
+               result = 1;
+               goto out;
+             }
+         }
+         break;
+
        default:
          /* Compare the section content byte for byte.  */
          assert (shdr1->sh_type == SHT_NOBITS
@@ -592,6 +701,10 @@ parse_opt (int key, char *arg,
       hash_inexact = true;
       break;
 
+    case OPT_IGNORE_BUILD_ID:
+      ignore_build_id = true;
+      break;
+
     default:
       return ARGP_ERR_UNKNOWN;
     }