Refactor elf_compare
authorMartin Liska <mliska@suse.cz>
Mon, 28 Nov 2022 13:10:36 +0000 (14:10 +0100)
committerMartin Liska <mliska@suse.cz>
Tue, 29 Nov 2022 09:33:22 +0000 (10:33 +0100)
src/ChangeLog:

* elfcompress.c (T_UNSET): Remove and use ch_type.
(T_DECOMPRESS): Likewise.
(T_COMPRESS_ZLIB): Likewise.
(T_COMPRESS_GNU): Likewise.
(enum ch_type): New.
(parse_opt): Parse to new ch_type.
(compress_section): Change gnu and compress arguments
to schtype (source compression) and dchtype (destination
compression).
(process_file): Use new enum type and adjusted compress_section.

src/elfcompress.c

index 51ff69d..eff765e 100644 (file)
@@ -48,13 +48,23 @@ static bool force = false;
 static bool permissive = false;
 static const char *foutput = NULL;
 
-#define T_UNSET 0
-#define T_DECOMPRESS 1    /* none */
-#define T_COMPRESS_ZLIB 2 /* zlib */
-#define T_COMPRESS_GNU  3 /* zlib-gnu */
+/* Compression algorithm, where all legal values for ch_type
+   (compression algorithm) do match the following enum.  */
+enum ch_type
+{
+  UNSET = -1,
+  NONE,
+  ZLIB,
+
+  /* Maximal supported ch_type.  */
+  MAXIMAL_CH_TYPE = ZLIB,
+
+  ZLIB_GNU = 1 << 16
+};
+
 #define WORD_BITS (8U * sizeof (unsigned int))
 
-static int type = T_UNSET;
+static enum ch_type type = UNSET;
 
 struct section_pattern
 {
@@ -120,22 +130,22 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
       break;
 
     case 't':
-      if (type != T_UNSET)
+      if (type != UNSET)
        argp_error (state, N_("-t option specified twice"));
 
       if (strcmp ("none", arg) == 0)
-       type = T_DECOMPRESS;
+       type = NONE;
       else if (strcmp ("zlib", arg) == 0 || strcmp ("zlib-gabi", arg) == 0)
-       type = T_COMPRESS_ZLIB;
+       type = ZLIB;
       else if (strcmp ("zlib-gnu", arg) == 0 || strcmp ("gnu", arg) == 0)
-       type = T_COMPRESS_GNU;
+       type = ZLIB_GNU;
       else
        argp_error (state, N_("unknown compression type '%s'"), arg);
       break;
 
     case ARGP_KEY_SUCCESS:
-      if (type == T_UNSET)
-       type = T_COMPRESS_ZLIB;
+      if (type == UNSET)
+       type = ZLIB;
       if (patterns == NULL)
        add_pattern (".?(z)debug*");
       break;
@@ -198,14 +208,19 @@ setshdrstrndx (Elf *elf, GElf_Ehdr *ehdr, size_t ndx)
 static int
 compress_section (Elf_Scn *scn, size_t orig_size, const char *name,
                  const char *newname, size_t ndx,
-                 bool gnu, bool compress, bool report_verbose)
+                 enum ch_type schtype, enum ch_type dchtype,
+                 bool report_verbose)
 {
+  /* We either compress or decompress.  */
+  assert (schtype == NONE || dchtype == NONE);
+  bool compress = dchtype != NONE;
+
   int res;
   unsigned int flags = compress && force ? ELF_CHF_FORCE : 0;
-  if (gnu)
+  if (schtype == ZLIB_GNU || dchtype == ZLIB_GNU)
     res = elf_compress_gnu (scn, compress ? 1 : 0, flags);
   else
-    res = elf_compress (scn, compress ? ELFCOMPRESS_ZLIB : 0, flags);
+    res = elf_compress (scn, dchtype, flags);
 
   if (res < 0)
     error (0, 0, "Couldn't decompress section [%zd] %s: %s",
@@ -446,20 +461,20 @@ process_file (const char *fname)
 
       if (section_name_matches (sname))
        {
-         if (!force && type == T_DECOMPRESS
+         if (!force && type == NONE
              && (shdr->sh_flags & SHF_COMPRESSED) == 0
              && !startswith (sname, ".zdebug"))
            {
              if (verbose > 0)
                printf ("[%zd] %s already decompressed\n", ndx, sname);
            }
-         else if (!force && type == T_COMPRESS_ZLIB
+         else if (!force && type == ZLIB
                   && (shdr->sh_flags & SHF_COMPRESSED) != 0)
            {
              if (verbose > 0)
                printf ("[%zd] %s already compressed\n", ndx, sname);
            }
-         else if (!force && type == T_COMPRESS_GNU
+         else if (!force && type == ZLIB_GNU
                   && startswith (sname, ".zdebug"))
            {
              if (verbose > 0)
@@ -471,9 +486,9 @@ process_file (const char *fname)
              set_section (sections, ndx);
              /* Check if we might want to change this section name.  */
              if (! adjust_names
-                 && ((type != T_COMPRESS_GNU
+                 && ((type != ZLIB_GNU
                       && startswith (sname, ".zdebug"))
-                     || (type == T_COMPRESS_GNU
+                     || (type == ZLIB_GNU
                          && startswith (sname, ".debug"))))
                adjust_names = true;
 
@@ -634,11 +649,11 @@ process_file (const char *fname)
      and keep track of whether or not to compress them (later in the
      fixup pass).  Also record the original size, so we can report the
      difference later when we do compress.  */
-  int shstrtab_compressed = T_UNSET;
+  enum ch_type shstrtab_compressed = UNSET;
   size_t shstrtab_size = 0;
   char *shstrtab_name = NULL;
   char *shstrtab_newname = NULL;
-  int symtab_compressed = T_UNSET;
+  enum ch_type symtab_compressed = UNSET;
   size_t symtab_size = 0;
   char *symtab_name = NULL;
   char *symtab_newname = NULL;
@@ -677,6 +692,38 @@ process_file (const char *fname)
             (de)compressed, invalidating the string pointers.  */
          sname = xstrdup (sname);
 
+         /* Detect source compression that is how is the section compressed
+            now.  */
+         GElf_Chdr chdr;
+         enum ch_type schtype = NONE;
+         if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+           {
+             if (gelf_getchdr (scn, &chdr) != NULL)
+               {
+                 schtype = (enum ch_type)chdr.ch_type;
+                 if (schtype == NONE)
+                   {
+                     error (0, 0, "Compression type for section %zd"
+                            " can't be zero ", ndx);
+                     goto cleanup;
+                   }
+                 else if (schtype > MAXIMAL_CH_TYPE)
+                   {
+                     error (0, 0, "Compression type (%d) for section %zd"
+                            " is unsupported ", schtype, ndx);
+                     goto cleanup;
+                   }
+               }
+             else
+               {
+                 error (0, 0, "Couldn't get chdr for section %zd", ndx);
+                 goto cleanup;
+               }
+           }
+         /* Set ZLIB compression manually for .zdebug* sections.  */
+         else if (startswith (sname, ".zdebug"))
+           schtype = ZLIB_GNU;
+
          /* We might want to decompress (and rename), but not
             compress during this pass since we might need the section
             data in later passes.  Skip those sections for now and
@@ -687,35 +734,32 @@ process_file (const char *fname)
 
          switch (type)
            {
-           case T_DECOMPRESS:
-             if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+           case NONE:
+             if (schtype != NONE)
                {
+                 if (schtype == ZLIB_GNU)
+                   {
+                     snamebuf[0] = '.';
+                     strcpy (&snamebuf[1], &sname[2]);
+                     newname = snamebuf;
+                   }
                  if (compress_section (scn, size, sname, NULL, ndx,
-                                       false, false, verbose > 0) < 0)
-                   goto cleanup;
-               }
-             else if (startswith (sname, ".zdebug"))
-               {
-                 snamebuf[0] = '.';
-                 strcpy (&snamebuf[1], &sname[2]);
-                 newname = snamebuf;
-                 if (compress_section (scn, size, sname, newname, ndx,
-                                       true, false, verbose > 0) < 0)
+                                       schtype, NONE, verbose > 0) < 0)
                    goto cleanup;
                }
              else if (verbose > 0)
                printf ("[%zd] %s already decompressed\n", ndx, sname);
              break;
 
-           case T_COMPRESS_GNU:
+           case ZLIB_GNU:
              if (startswith (sname, ".debug"))
                {
-                 if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+                 if (schtype == ZLIB)
                    {
                      /* First decompress to recompress GNU style.
                         Don't report even when verbose.  */
                      if (compress_section (scn, size, sname, NULL, ndx,
-                                           false, false, false) < 0)
+                                           schtype, NONE, false) < 0)
                        goto cleanup;
                    }
 
@@ -729,7 +773,7 @@ process_file (const char *fname)
                      if (ndx == shdrstrndx)
                        {
                          shstrtab_size = size;
-                         shstrtab_compressed = T_COMPRESS_GNU;
+                         shstrtab_compressed = ZLIB_GNU;
                          if (shstrtab_name != NULL
                              || shstrtab_newname != NULL)
                            {
@@ -745,7 +789,7 @@ process_file (const char *fname)
                      else
                        {
                          symtab_size = size;
-                         symtab_compressed = T_COMPRESS_GNU;
+                         symtab_compressed = ZLIB_GNU;
                          symtab_name = xstrdup (sname);
                          symtab_newname = xstrdup (newname);
                        }
@@ -753,7 +797,7 @@ process_file (const char *fname)
                  else
                    {
                      int result = compress_section (scn, size, sname, newname,
-                                                    ndx, true, true,
+                                                    ndx, NONE, type,
                                                     verbose > 0);
                      if (result < 0)
                        goto cleanup;
@@ -764,7 +808,7 @@ process_file (const char *fname)
                }
              else if (verbose >= 0)
                {
-                 if (startswith (sname, ".zdebug"))
+                 if (schtype == ZLIB_GNU)
                    printf ("[%zd] %s unchanged, already GNU compressed\n",
                            ndx, sname);
                  else
@@ -773,15 +817,15 @@ process_file (const char *fname)
                }
              break;
 
-           case T_COMPRESS_ZLIB:
+           case ZLIB:
              if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
                {
-                 if (startswith (sname, ".zdebug"))
+                 if (schtype == ZLIB_GNU)
                    {
                      /* First decompress to recompress zlib style.
                         Don't report even when verbose.  */
                      if (compress_section (scn, size, sname, NULL, ndx,
-                                           true, false, false) < 0)
+                                           schtype, NONE, false) < 0)
                        goto cleanup;
 
                      snamebuf[0] = '.';
@@ -794,7 +838,7 @@ process_file (const char *fname)
                      if (ndx == shdrstrndx)
                        {
                          shstrtab_size = size;
-                         shstrtab_compressed = T_COMPRESS_ZLIB;
+                         shstrtab_compressed = ZLIB;
                          if (shstrtab_name != NULL
                              || shstrtab_newname != NULL)
                            {
@@ -811,19 +855,22 @@ process_file (const char *fname)
                      else
                        {
                          symtab_size = size;
-                         symtab_compressed = T_COMPRESS_ZLIB;
+                         symtab_compressed = ZLIB;
                          symtab_name = xstrdup (sname);
                          symtab_newname = (newname == NULL
                                            ? NULL : xstrdup (newname));
                        }
                    }
                  else if (compress_section (scn, size, sname, newname, ndx,
-                                            false, true, verbose > 0) < 0)
+                                            NONE, type, verbose > 0) < 0)
                    goto cleanup;
                }
              else if (verbose > 0)
                printf ("[%zd] %s already compressed\n", ndx, sname);
              break;
+
+           case UNSET:
+             break;
            }
 
          free (sname);
@@ -903,28 +950,28 @@ process_file (const char *fname)
              /* If the section is (still) compressed we'll need to
                 uncompress it first to adjust the data, then
                 recompress it in the fixup pass.  */
-             if (symtab_compressed == T_UNSET)
+             if (symtab_compressed == UNSET)
                {
                  size_t size = shdr->sh_size;
                  if ((shdr->sh_flags == SHF_COMPRESSED) != 0)
                    {
                      /* Don't report the (internal) uncompression.  */
                      if (compress_section (newscn, size, sname, NULL, ndx,
-                                           false, false, false) < 0)
+                                           ZLIB, NONE, false) < 0)
                        goto cleanup;
 
                      symtab_size = size;
-                     symtab_compressed = T_COMPRESS_ZLIB;
+                     symtab_compressed = ZLIB;
                    }
                  else if (startswith (name, ".zdebug"))
                    {
                      /* Don't report the (internal) uncompression.  */
                      if (compress_section (newscn, size, sname, NULL, ndx,
-                                           true, false, false) < 0)
+                                           ZLIB_GNU, NONE, false) < 0)
                        goto cleanup;
 
                      symtab_size = size;
-                     symtab_compressed = T_COMPRESS_GNU;
+                     symtab_compressed = ZLIB_GNU;
                    }
                }
 
@@ -1037,7 +1084,7 @@ process_file (const char *fname)
         or if the section was already compressed (and the user didn't
         ask for decompression).  Note somewhat identical code for
         symtab below.  */
-      if (shstrtab_compressed == T_UNSET)
+      if (shstrtab_compressed == UNSET)
        {
          /* The user didn't ask for compression, but maybe it was
             compressed in the original ELF file.  */
@@ -1067,18 +1114,18 @@ process_file (const char *fname)
 
          shstrtab_size = shdr->sh_size;
          if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
-           shstrtab_compressed = T_COMPRESS_ZLIB;
+           shstrtab_compressed = ZLIB;
          else if (startswith (shstrtab_name, ".zdebug"))
-           shstrtab_compressed = T_COMPRESS_GNU;
+           shstrtab_compressed = ZLIB_GNU;
        }
 
       /* Should we (re)compress?  */
-      if (shstrtab_compressed != T_UNSET)
+      if (shstrtab_compressed != UNSET)
        {
          if (compress_section (scn, shstrtab_size, shstrtab_name,
                                shstrtab_newname, shdrstrndx,
-                               shstrtab_compressed == T_COMPRESS_GNU,
-                               true, verbose > 0) < 0)
+                               NONE, shstrtab_compressed,
+                               verbose > 0) < 0)
            goto cleanup;
        }
     }
@@ -1178,7 +1225,7 @@ process_file (const char *fname)
                 us to, or if the section was already compressed (and
                 the user didn't ask for decompression).  Note
                 somewhat identical code for shstrtab above.  */
-             if (symtab_compressed == T_UNSET)
+             if (symtab_compressed == UNSET)
                {
                  /* The user didn't ask for compression, but maybe it was
                     compressed in the original ELF file.  */
@@ -1208,18 +1255,18 @@ process_file (const char *fname)
 
                  symtab_size = shdr->sh_size;
                  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
-                   symtab_compressed = T_COMPRESS_ZLIB;
+                   symtab_compressed = ZLIB;
                  else if (startswith (symtab_name, ".zdebug"))
-                   symtab_compressed = T_COMPRESS_GNU;
+                   symtab_compressed = ZLIB_GNU;
                }
 
              /* Should we (re)compress?  */
-             if (symtab_compressed != T_UNSET)
+             if (symtab_compressed != UNSET)
                {
                  if (compress_section (scn, symtab_size, symtab_name,
                                        symtab_newname, symtabndx,
-                                       symtab_compressed == T_COMPRESS_GNU,
-                                       true, verbose > 0) < 0)
+                                       NONE, symtab_compressed,
+                                       verbose > 0) < 0)
                    goto cleanup;
                }
            }