LCOV - code coverage report
Current view: top level - src - elfcompress.c (source / functions) Hit Total Coverage
Test: elfutils-0.189 Lines: 434 652 66.6 %
Date: 2023-04-14 15:57:06 Functions: 9 9 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 277 439 63.1 %

           Branch data     Line data    Source code
       1                 :            : /* Compress or decompress an ELF file.
       2                 :            :    Copyright (C) 2015, 2016, 2018 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            : 
       5                 :            :    This file is free software; you can redistribute it and/or modify
       6                 :            :    it under the terms of the GNU General Public License as published by
       7                 :            :    the Free Software Foundation; either version 3 of the License, or
       8                 :            :    (at your option) any later version.
       9                 :            : 
      10                 :            :    elfutils is distributed in the hope that it will be useful, but
      11                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13                 :            :    GNU General Public License for more details.
      14                 :            : 
      15                 :            :    You should have received a copy of the GNU General Public License
      16                 :            :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      17                 :            : 
      18                 :            : #include <config.h>
      19                 :            : #include <assert.h>
      20                 :            : #include <argp.h>
      21                 :            : #include <stdbool.h>
      22                 :            : #include <stdlib.h>
      23                 :            : #include <inttypes.h>
      24                 :            : #include <stdio.h>
      25                 :            : #include <string.h>
      26                 :            : #include <locale.h>
      27                 :            : #include <fcntl.h>
      28                 :            : #include <fnmatch.h>
      29                 :            : #include <sys/types.h>
      30                 :            : #include <sys/stat.h>
      31                 :            : #include <unistd.h>
      32                 :            : #include ELFUTILS_HEADER(elf)
      33                 :            : #include ELFUTILS_HEADER(ebl)
      34                 :            : #include ELFUTILS_HEADER(dwelf)
      35                 :            : #include <gelf.h>
      36                 :            : #include "system.h"
      37                 :            : #include "libeu.h"
      38                 :            : #include "printversion.h"
      39                 :            : 
      40                 :            : /* Name and version of program.  */
      41                 :            : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
      42                 :            : 
      43                 :            : /* Bug report address.  */
      44                 :            : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
      45                 :            : 
      46                 :            : static int verbose = 0; /* < 0, no warnings, > 0 extra verbosity.  */
      47                 :            : static bool force = false;
      48                 :            : static bool permissive = false;
      49                 :            : static const char *foutput = NULL;
      50                 :            : 
      51                 :            : /* Compression algorithm, where all legal values for ch_type
      52                 :            :    (compression algorithm) do match the following enum.  */
      53                 :            : enum ch_type
      54                 :            : {
      55                 :            :   UNSET = -1,
      56                 :            :   NONE,
      57                 :            :   ZLIB,
      58                 :            :   ZSTD,
      59                 :            : 
      60                 :            :   /* Maximal supported ch_type.  */
      61                 :            :   MAXIMAL_CH_TYPE = ZSTD,
      62                 :            : 
      63                 :            :   ZLIB_GNU = 1 << 16
      64                 :            : };
      65                 :            : 
      66                 :            : #define WORD_BITS (8U * sizeof (unsigned int))
      67                 :            : 
      68                 :            : static enum ch_type type = UNSET;
      69                 :            : 
      70                 :            : struct section_pattern
      71                 :            : {
      72                 :            :   char *pattern;
      73                 :            :   struct section_pattern *next;
      74                 :            : };
      75                 :            : 
      76                 :            : static struct section_pattern *patterns = NULL;
      77                 :            : 
      78                 :            : static void
      79                 :        214 : add_pattern (const char *pattern)
      80                 :            : {
      81                 :        214 :   struct section_pattern *p = xmalloc (sizeof *p);
      82                 :        214 :   p->pattern = xstrdup (pattern);
      83                 :        214 :   p->next = patterns;
      84                 :        214 :   patterns = p;
      85                 :        214 : }
      86                 :            : 
      87                 :            : static void
      88                 :        214 : free_patterns (void)
      89                 :            : {
      90                 :        214 :   struct section_pattern *pattern = patterns;
      91         [ +  + ]:        428 :   while (pattern != NULL)
      92                 :            :     {
      93                 :        214 :       struct section_pattern *p = pattern;
      94                 :        214 :       pattern = p->next;
      95                 :        214 :       free (p->pattern);
      96                 :        214 :       free (p);
      97                 :            :     }
      98                 :        214 : }
      99                 :            : 
     100                 :            : static error_t
     101                 :       1710 : parse_opt (int key, char *arg __attribute__ ((unused)),
     102                 :            :            struct argp_state *state __attribute__ ((unused)))
     103                 :            : {
     104   [ +  +  +  -  :       1710 :   switch (key)
          +  +  +  +  -  
                   +  + ]
     105                 :            :     {
     106                 :        192 :     case 'v':
     107                 :        192 :       verbose++;
     108                 :        192 :       break;
     109                 :            : 
     110                 :         18 :     case 'q':
     111                 :         18 :       verbose--;
     112                 :         18 :       break;
     113                 :            : 
     114                 :         21 :     case 'f':
     115                 :         21 :       force = true;
     116                 :         21 :       break;
     117                 :            : 
     118                 :          0 :     case 'p':
     119                 :          0 :       permissive = true;
     120                 :          0 :       break;
     121                 :            : 
     122                 :          9 :     case 'n':
     123                 :          9 :       add_pattern (arg);
     124                 :          9 :       break;
     125                 :            : 
     126                 :        204 :     case 'o':
     127         [ -  + ]:        204 :       if (foutput != NULL)
     128                 :          0 :         argp_error (state, N_("-o option specified twice"));
     129                 :            :       else
     130                 :        204 :         foutput = arg;
     131                 :            :       break;
     132                 :            : 
     133                 :        196 :     case 't':
     134         [ -  + ]:        196 :       if (type != UNSET)
     135                 :          0 :         argp_error (state, N_("-t option specified twice"));
     136                 :            : 
     137         [ +  + ]:        196 :       if (strcmp ("none", arg) == 0)
     138                 :         73 :         type = NONE;
     139   [ +  +  -  + ]:        123 :       else if (strcmp ("zlib", arg) == 0 || strcmp ("zlib-gabi", arg) == 0)
     140                 :         25 :         type = ZLIB;
     141   [ +  +  +  + ]:         98 :       else if (strcmp ("zlib-gnu", arg) == 0 || strcmp ("gnu", arg) == 0)
     142                 :         50 :         type = ZLIB_GNU;
     143         [ +  - ]:         48 :       else if (strcmp ("zstd", arg) == 0)
     144                 :            : #ifdef USE_ZSTD_COMPRESS
     145                 :         48 :         type = ZSTD;
     146                 :            : #else
     147                 :            :         argp_error (state, N_("ZSTD support is not enabled"));
     148                 :            : #endif
     149                 :            :       else
     150                 :          0 :         argp_error (state, N_("unknown compression type '%s'"), arg);
     151                 :            :       break;
     152                 :            : 
     153                 :        214 :     case ARGP_KEY_SUCCESS:
     154         [ +  + ]:        214 :       if (type == UNSET)
     155                 :         18 :         type = ZLIB;
     156         [ +  + ]:        214 :       if (patterns == NULL)
     157                 :        205 :         add_pattern (".?(z)debug*");
     158                 :            :       break;
     159                 :            : 
     160                 :          0 :     case ARGP_KEY_NO_ARGS:
     161                 :            :       /* We need at least one input file.  */
     162                 :          0 :       argp_error (state, N_("No input file given"));
     163                 :          0 :       break;
     164                 :            : 
     165                 :        214 :     case ARGP_KEY_ARGS:
     166   [ +  +  -  + ]:        214 :       if (foutput != NULL && state->argc - state->next > 1)
     167                 :          0 :         argp_error (state,
     168                 :            :                     N_("Only one input file allowed together with '-o'"));
     169                 :            :       /* We only use this for checking the number of arguments, we don't
     170                 :            :          actually want to consume them.  */
     171                 :            :       FALLTHROUGH;
     172                 :            :     default:
     173                 :            :       return ARGP_ERR_UNKNOWN;
     174                 :            :     }
     175                 :            :   return 0;
     176                 :            : }
     177                 :            : 
     178                 :            : static bool
     179                 :       4557 : section_name_matches (const char *name)
     180                 :            : {
     181                 :       4557 :   struct section_pattern *pattern = patterns;
     182         [ +  + ]:       7926 :   while (pattern != NULL)
     183                 :            :     {
     184         [ +  + ]:       4557 :       if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
     185                 :            :         return true;
     186                 :       3369 :       pattern = pattern->next;
     187                 :            :     }
     188                 :            :   return false;
     189                 :            : }
     190                 :            : 
     191                 :            : static int
     192                 :        230 : setshdrstrndx (Elf *elf, GElf_Ehdr *ehdr, size_t ndx)
     193                 :            : {
     194         [ +  - ]:        230 :   if (ndx < SHN_LORESERVE)
     195                 :        230 :     ehdr->e_shstrndx = ndx;
     196                 :            :   else
     197                 :            :     {
     198                 :          0 :       ehdr->e_shstrndx = SHN_XINDEX;
     199                 :          0 :       Elf_Scn *zscn = elf_getscn (elf, 0);
     200                 :          0 :       GElf_Shdr zshdr_mem;
     201                 :          0 :       GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
     202         [ #  # ]:          0 :       if (zshdr == NULL)
     203                 :          0 :         return -1;
     204                 :          0 :       zshdr->sh_link = ndx;
     205         [ #  # ]:          0 :       if (gelf_update_shdr (zscn, zshdr) == 0)
     206                 :            :         return -1;
     207                 :            :     }
     208                 :            : 
     209         [ -  + ]:        230 :   if (gelf_update_ehdr (elf, ehdr) == 0)
     210                 :          0 :     return -1;
     211                 :            : 
     212                 :            :   return 0;
     213                 :            : }
     214                 :            : 
     215                 :            : static int
     216                 :       1249 : compress_section (Elf_Scn *scn, size_t orig_size, const char *name,
     217                 :            :                   const char *newname, size_t ndx,
     218                 :            :                   enum ch_type schtype, enum ch_type dchtype,
     219                 :            :                   bool report_verbose)
     220                 :            : {
     221                 :            :   /* We either compress or decompress.  */
     222         [ -  + ]:       1249 :   assert (schtype == NONE || dchtype == NONE);
     223                 :       1249 :   bool compress = dchtype != NONE;
     224                 :            : 
     225                 :       1249 :   int res;
     226   [ +  +  +  + ]:       1249 :   unsigned int flags = compress && force ? ELF_CHF_FORCE : 0;
     227         [ +  + ]:       1249 :   if (schtype == ZLIB_GNU || dchtype == ZLIB_GNU)
     228                 :        481 :     res = elf_compress_gnu (scn, compress ? 1 : 0, flags);
     229                 :            :   else
     230                 :        768 :     res = elf_compress (scn, dchtype, flags);
     231                 :            : 
     232         [ -  + ]:       1249 :   if (res < 0)
     233         [ #  # ]:          0 :     error (0, 0, "Couldn't %s section [%zd] %s: %s",
     234                 :            :            compress ? "compress" : "decompress",
     235                 :            :            ndx, name, elf_errmsg (-1));
     236                 :            :   else
     237                 :            :     {
     238         [ +  + ]:       1249 :       if (compress && res == 0)
     239                 :            :         {
     240         [ +  - ]:        136 :           if (verbose >= 0)
     241                 :        136 :             printf ("[%zd] %s NOT compressed, wouldn't be smaller\n",
     242                 :            :                     ndx, name);
     243                 :            :         }
     244                 :            : 
     245         [ +  + ]:       1249 :       if (report_verbose && res > 0)
     246                 :            :         {
     247         [ +  + ]:        718 :           printf ("[%zd] %s %s", ndx, name,
     248                 :            :                   compress ? "compressed" : "decompressed");
     249         [ +  + ]:        718 :           if (newname != NULL)
     250                 :        196 :             printf (" -> %s", newname);
     251                 :            : 
     252                 :            :           /* Reload shdr, it has changed.  */
     253                 :        718 :           GElf_Shdr shdr_mem;
     254                 :        718 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     255         [ -  + ]:        718 :           if (shdr == NULL)
     256                 :            :             {
     257                 :          0 :               error (0, 0, "Couldn't get shdr for section [%zd]", ndx);
     258                 :          0 :               return -1;
     259                 :            :             }
     260                 :        718 :           float new = shdr->sh_size;
     261         [ +  - ]:        718 :           float orig = orig_size ?: 1;
     262                 :        718 :           printf (" (%zu => %" PRIu64 " %.2f%%)\n",
     263                 :        718 :                   orig_size, shdr->sh_size, (new / orig) * 100);
     264                 :            :         }
     265                 :            :     }
     266                 :            : 
     267                 :            :   return res;
     268                 :            : }
     269                 :            : 
     270                 :            : static void
     271                 :       1188 : set_section (unsigned int *sections, size_t ndx)
     272                 :            : {
     273                 :       1188 :   sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS));
     274                 :            : }
     275                 :            : 
     276                 :            : static bool
     277                 :       4557 : get_section (unsigned int *sections, size_t ndx)
     278                 :            : {
     279                 :       4557 :   return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0;
     280                 :            : }
     281                 :            : 
     282                 :            : /* How many sections are we going to change?  */
     283                 :            : static size_t
     284                 :         26 : get_sections (unsigned int *sections, size_t shnum)
     285                 :            : {
     286                 :         26 :   size_t s = 0;
     287         [ +  + ]:         69 :   for (size_t i = 0; i < shnum / WORD_BITS + 1; i++)
     288                 :         43 :     s += __builtin_popcount (sections[i]);
     289                 :         26 :   return s;
     290                 :            : }
     291                 :            : 
     292                 :            : /* Return compression type of a given section SHDR.  */
     293                 :            : 
     294                 :            : static enum ch_type
     295                 :       2376 : get_section_chtype (Elf_Scn *scn, GElf_Shdr *shdr, const char *sname,
     296                 :            :                     size_t ndx)
     297                 :            : {
     298                 :       2376 :   enum ch_type chtype = UNSET;
     299         [ +  + ]:       2376 :   if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
     300                 :            :     {
     301                 :        624 :       GElf_Chdr chdr;
     302         [ +  - ]:        624 :       if (gelf_getchdr (scn, &chdr) != NULL)
     303                 :            :         {
     304                 :        624 :           chtype = (enum ch_type)chdr.ch_type;
     305         [ -  + ]:        624 :           if (chtype == NONE)
     306                 :            :             {
     307                 :          0 :               error (0, 0, "Compression type for section %zd"
     308                 :            :                      " can't be zero ", ndx);
     309                 :          0 :               chtype = UNSET;
     310                 :            :             }
     311         [ -  + ]:        624 :           else if (chtype > MAXIMAL_CH_TYPE)
     312                 :            :             {
     313                 :          0 :               error (0, 0, "Compression type (%d) for section %zd"
     314                 :            :                      " is unsupported ", chtype, ndx);
     315                 :          0 :               chtype = UNSET;
     316                 :            :             }
     317                 :            :         }
     318                 :            :       else
     319                 :        624 :         error (0, 0, "Couldn't get chdr for section %zd", ndx);
     320                 :            :     }
     321                 :            :   /* Set ZLIB_GNU compression manually for .zdebug* sections.  */
     322         [ +  + ]:       1752 :   else if (startswith (sname, ".zdebug"))
     323                 :            :     chtype = ZLIB_GNU;
     324                 :            :   else
     325                 :       1508 :     chtype = NONE;
     326                 :            : 
     327                 :       2376 :   return chtype;
     328                 :            : }
     329                 :            : 
     330                 :            : static int
     331                 :        230 : process_file (const char *fname)
     332                 :            : {
     333         [ +  + ]:        230 :   if (verbose > 0)
     334                 :        192 :     printf ("processing: %s\n", fname);
     335                 :            : 
     336                 :            :   /* The input ELF.  */
     337                 :        230 :   int fd = -1;
     338                 :        230 :   Elf *elf = NULL;
     339                 :            : 
     340                 :            :   /* The output ELF.  */
     341                 :        230 :   char *fnew = NULL;
     342                 :        230 :   int fdnew = -1;
     343                 :        230 :   Elf *elfnew = NULL;
     344                 :            : 
     345                 :            :   /* Buffer for (one) new section name if necessary.  */
     346                 :        230 :   char *snamebuf = NULL;
     347                 :            : 
     348                 :            :   /* String table (and symbol table), if section names need adjusting.  */
     349                 :        230 :   Dwelf_Strtab *names = NULL;
     350                 :        230 :   Dwelf_Strent **scnstrents = NULL;
     351                 :        230 :   Dwelf_Strent **symstrents = NULL;
     352                 :        230 :   char **scnnames = NULL;
     353                 :            : 
     354                 :            :   /* Section data from names.  */
     355                 :        230 :   void *namesbuf = NULL;
     356                 :            : 
     357                 :            :   /* Which sections match and need to be (un)compressed.  */
     358                 :        230 :   unsigned int *sections = NULL;
     359                 :            : 
     360                 :            :   /* How many sections are we talking about?  */
     361                 :        230 :   size_t shnum = 0;
     362                 :        230 :   int res = 1;
     363                 :            : 
     364                 :        230 :   fd = open (fname, O_RDONLY);
     365         [ -  + ]:        230 :   if (fd < 0)
     366                 :            :     {
     367                 :          0 :       error (0, errno, "Couldn't open %s\n", fname);
     368                 :          0 :       goto cleanup;
     369                 :            :     }
     370                 :            : 
     371                 :        230 :   elf = elf_begin (fd, ELF_C_READ, NULL);
     372         [ -  + ]:        230 :   if (elf == NULL)
     373                 :            :     {
     374                 :          0 :       error (0, 0, "Couldn't open ELF file %s for reading: %s",
     375                 :            :              fname, elf_errmsg (-1));
     376                 :          0 :       goto cleanup;
     377                 :            :     }
     378                 :            : 
     379                 :            :   /* We don't handle ar files (or anything else), we probably should.  */
     380                 :        230 :   Elf_Kind kind = elf_kind (elf);
     381         [ -  + ]:        230 :   if (kind != ELF_K_ELF)
     382                 :            :     {
     383         [ #  # ]:          0 :       if (kind == ELF_K_AR)
     384                 :          0 :         error (0, 0, "Cannot handle ar files: %s", fname);
     385                 :            :       else
     386                 :          0 :         error (0, 0, "Unknown file type: %s", fname);
     387                 :          0 :       goto cleanup;
     388                 :            :     }
     389                 :            : 
     390                 :        230 :   struct stat st;
     391         [ -  + ]:        230 :   if (fstat (fd, &st) != 0)
     392                 :            :     {
     393                 :          0 :       error (0, errno, "Couldn't fstat %s", fname);
     394                 :          0 :       goto cleanup;
     395                 :            :     }
     396                 :            : 
     397                 :        230 :   GElf_Ehdr ehdr;
     398         [ -  + ]:        230 :   if (gelf_getehdr (elf, &ehdr) == NULL)
     399                 :            :     {
     400                 :          0 :       error (0, 0, "Couldn't get ehdr for %s: %s", fname, elf_errmsg (-1));
     401                 :          0 :       goto cleanup;
     402                 :            :     }
     403                 :            : 
     404                 :            :   /* Get the section header string table.  */
     405                 :        230 :   size_t shdrstrndx;
     406         [ -  + ]:        230 :   if (elf_getshdrstrndx (elf, &shdrstrndx) != 0)
     407                 :            :     {
     408                 :          0 :       error (0, 0, "Couldn't get section header string table index in %s: %s",
     409                 :            :              fname, elf_errmsg (-1));
     410                 :          0 :       goto cleanup;
     411                 :            :     }
     412                 :            : 
     413                 :            :   /* How many sections are we talking about?  */
     414         [ -  + ]:        230 :   if (elf_getshdrnum (elf, &shnum) != 0)
     415                 :            :     {
     416                 :          0 :       error (0, 0, "Couldn't get number of sections in %s: %s",
     417                 :            :              fname, elf_errmsg (1));
     418                 :          0 :       goto cleanup;
     419                 :            :     }
     420                 :            : 
     421         [ -  + ]:        230 :   if (shnum == 0)
     422                 :            :     {
     423                 :          0 :       error (0, 0, "ELF file %s has no sections", fname);
     424                 :          0 :       goto cleanup;
     425                 :            :     }
     426                 :            : 
     427                 :        230 :   sections = xcalloc (shnum / 8 + 1, sizeof (unsigned int));
     428                 :            : 
     429                 :        230 :   size_t phnum;
     430         [ -  + ]:        230 :   if (elf_getphdrnum (elf, &phnum) != 0)
     431                 :            :     {
     432                 :          0 :       error (0, 0, "Couldn't get phdrnum: %s", elf_errmsg (-1));
     433                 :          0 :       goto cleanup;
     434                 :            :     }
     435                 :            : 
     436                 :            :   /* Whether we need to adjust any section names (going to/from GNU
     437                 :            :      naming).  If so we'll need to build a new section header string
     438                 :            :      table.  */
     439                 :        230 :   bool adjust_names = false;
     440                 :            : 
     441                 :            :   /* If there are phdrs we want to maintain the layout of the
     442                 :            :      allocated sections in the file.  */
     443                 :        230 :   bool layout = phnum != 0;
     444                 :            : 
     445                 :            :   /* While going through all sections keep track of last section data
     446                 :            :      offset if needed to keep the layout.  We are responsible for
     447                 :            :      adding the section offsets and headers (e_shoff) in that case
     448                 :            :      (which we will place after the last section).  */
     449                 :        230 :   GElf_Off last_offset = 0;
     450         [ +  + ]:        230 :   if (layout)
     451                 :        213 :     last_offset = (ehdr.e_phoff
     452                 :        213 :                    + gelf_fsize (elf, ELF_T_PHDR, phnum, EV_CURRENT));
     453                 :            : 
     454                 :            :   /* Which section, if any, is a symbol table that shares a string
     455                 :            :      table with the section header string table?  */
     456                 :            :   size_t symtabndx = 0;
     457                 :            : 
     458                 :            :   /* We do three passes over all sections.
     459                 :            : 
     460                 :            :      First an inspection pass over the old Elf to see which section
     461                 :            :      data needs to be copied and/or transformed, which sections need a
     462                 :            :      names change and whether there is a symbol table that might need
     463                 :            :      to be adjusted be if the section header name table is changed.
     464                 :            : 
     465                 :            :      If nothing needs changing, and the input and output file are the
     466                 :            :      same, we are done.
     467                 :            : 
     468                 :            :      Second a collection pass that creates the Elf sections and copies
     469                 :            :      the data.  This pass will compress/decompress section data when
     470                 :            :      needed.  And it will collect all data needed if we'll need to
     471                 :            :      construct a new string table. Afterwards the new string table is
     472                 :            :      constructed.
     473                 :            : 
     474                 :            :      Third a fixup/adjustment pass over the new Elf that will adjust
     475                 :            :      any section references (names) and adjust the layout based on the
     476                 :            :      new sizes of the sections if necessary.  This pass is optional if
     477                 :            :      we aren't responsible for the layout and the section header
     478                 :            :      string table hasn't been changed.  */
     479                 :            : 
     480                 :            :   /* Inspection pass.  */
     481                 :            :   size_t maxnamelen = 0;
     482                 :            :   Elf_Scn *scn = NULL;
     483         [ +  + ]:       4787 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     484                 :            :     {
     485                 :       4557 :       size_t ndx = elf_ndxscn (scn);
     486         [ -  + ]:       4557 :       if (ndx > shnum)
     487                 :            :         {
     488                 :          0 :           error (0, 0, "Unexpected section number %zd, expected only %zd",
     489                 :            :                  ndx, shnum);
     490                 :          0 :           goto cleanup;
     491                 :            :         }
     492                 :            : 
     493                 :       4557 :       GElf_Shdr shdr_mem;
     494                 :       4557 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     495         [ -  + ]:       4557 :       if (shdr == NULL)
     496                 :            :         {
     497                 :          0 :           error (0, 0, "Couldn't get shdr for section %zd", ndx);
     498                 :          0 :           goto cleanup;
     499                 :            :         }
     500                 :            : 
     501                 :       4557 :       const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
     502         [ -  + ]:       4557 :       if (sname == NULL)
     503                 :            :         {
     504                 :          0 :           error (0, 0, "Couldn't get name for section %zd", ndx);
     505                 :          0 :           goto cleanup;
     506                 :            :         }
     507                 :            : 
     508         [ +  + ]:       4557 :       if (section_name_matches (sname))
     509                 :            :         {
     510                 :       1188 :           enum ch_type schtype = get_section_chtype (scn, shdr, sname, ndx);
     511   [ +  +  +  + ]:       1188 :           if (!force && verbose > 0)
     512                 :            :             {
     513                 :            :               /* The current compression matches the final one.  */
     514         [ +  + ]:        976 :               if (type == schtype)
     515   [ +  -  -  - ]:        122 :                 switch (type)
     516                 :            :                   {
     517                 :            :                   case NONE:
     518                 :        122 :                     printf ("[%zd] %s already decompressed\n", ndx, sname);
     519                 :            :                     break;
     520                 :            :                   case ZLIB:
     521                 :            :                   case ZSTD:
     522                 :          0 :                     printf ("[%zd] %s already compressed\n", ndx, sname);
     523                 :            :                     break;
     524                 :            :                   case ZLIB_GNU:
     525                 :          0 :                     printf ("[%zd] %s already GNU compressed\n", ndx, sname);
     526                 :            :                     break;
     527                 :          0 :                   default:
     528                 :          0 :                     abort ();
     529                 :            :                   }
     530                 :       1066 :             }
     531                 :            : 
     532         [ +  - ]:       1188 :           if (shdr->sh_type != SHT_NOBITS
     533         [ +  - ]:       1188 :               && (shdr->sh_flags & SHF_ALLOC) == 0)
     534                 :            :             {
     535                 :       1188 :               set_section (sections, ndx);
     536                 :            :               /* Check if we might want to change this section name.  */
     537         [ +  + ]:       1188 :               if (! adjust_names
     538         [ +  + ]:        773 :                   && ((type != ZLIB_GNU
     539         [ +  + ]:        707 :                        && startswith (sname, ".zdebug"))
     540         [ +  + ]:        741 :                       || (type == ZLIB_GNU
     541         [ -  + ]:         66 :                           && startswith (sname, ".debug"))))
     542                 :            :                 adjust_names = true;
     543                 :            : 
     544                 :            :               /* We need a buffer this large if we change the names.  */
     545         [ +  + ]:       1090 :               if (adjust_names)
     546                 :            :                 {
     547                 :        513 :                   size_t slen = strlen (sname);
     548                 :        513 :                   if (slen > maxnamelen)
     549                 :            :                     maxnamelen = slen;
     550                 :            :                 }
     551                 :            :             }
     552                 :            :           else
     553         [ #  # ]:          0 :             if (verbose >= 0)
     554         [ #  # ]:          0 :               printf ("[%zd] %s ignoring %s section\n", ndx, sname,
     555                 :            :                       (shdr->sh_type == SHT_NOBITS ? "no bits" : "allocated"));
     556                 :            :         }
     557                 :            : 
     558         [ +  + ]:       4557 :       if (shdr->sh_type == SHT_SYMTAB)
     559                 :            :         {
     560                 :            :           /* Check if we might have to adjust the symbol name indexes.  */
     561         [ +  + ]:        230 :           if (shdr->sh_link == shdrstrndx)
     562                 :            :             {
     563         [ -  + ]:         96 :               if (symtabndx != 0)
     564                 :            :                 {
     565                 :          0 :                   error (0, 0,
     566                 :            :                          "Multiple symbol tables (%zd, %zd) using the same string table unsupported", symtabndx, ndx);
     567                 :          0 :                   goto cleanup;
     568                 :            :                 }
     569                 :            :               symtabndx = ndx;
     570                 :            :             }
     571                 :            :         }
     572                 :            : 
     573                 :            :       /* Keep track of last allocated data offset.  */
     574         [ +  + ]:       4557 :       if (layout)
     575         [ +  + ]:       4022 :         if ((shdr->sh_flags & SHF_ALLOC) != 0)
     576                 :            :           {
     577                 :       4432 :             GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
     578         [ +  + ]:       2216 :                                               ? shdr->sh_size : 0);
     579                 :       2216 :             if (last_offset < off)
     580                 :            :               last_offset = off;
     581                 :            :           }
     582                 :            :     }
     583                 :            : 
     584   [ +  +  -  + ]:        256 :   if (foutput == NULL && get_sections (sections, shnum) == 0)
     585                 :            :     {
     586         [ #  # ]:          0 :       if (verbose > 0)
     587                 :          0 :         printf ("Nothing to do.\n");
     588                 :          0 :       res = 0;
     589                 :          0 :       goto cleanup;
     590                 :            :     }
     591                 :            : 
     592         [ +  + ]:        230 :   if (adjust_names)
     593                 :            :     {
     594                 :         98 :       names = dwelf_strtab_init (true);
     595         [ -  + ]:         98 :       if (names == NULL)
     596                 :            :         {
     597                 :          0 :           error (0, 0, "Not enough memory for new strtab");
     598                 :          0 :           goto cleanup;
     599                 :            :         }
     600                 :         98 :       scnstrents = xmalloc (shnum
     601                 :            :                             * sizeof (Dwelf_Strent *));
     602                 :         98 :       scnnames = xcalloc (shnum, sizeof (char *));
     603                 :            :     }
     604                 :            : 
     605                 :            :   /* Create a new (temporary) ELF file for the result.  */
     606         [ +  + ]:        230 :   if (foutput == NULL)
     607                 :            :     {
     608                 :         26 :       size_t fname_len = strlen (fname);
     609                 :         26 :       fnew = xmalloc (fname_len + sizeof (".XXXXXX"));
     610                 :         26 :       strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
     611                 :         26 :       fdnew = mkstemp (fnew);
     612                 :            :     }
     613                 :            :   else
     614                 :            :     {
     615                 :        204 :       fnew = xstrdup (foutput);
     616                 :        204 :       fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
     617                 :            :     }
     618                 :            : 
     619         [ -  + ]:        230 :   if (fdnew < 0)
     620                 :            :     {
     621                 :          0 :       error (0, errno, "Couldn't create output file %s", fnew);
     622                 :            :       /* Since we didn't create it we don't want to try to unlink it.  */
     623                 :          0 :       free (fnew);
     624                 :          0 :       fnew = NULL;
     625                 :          0 :       goto cleanup;
     626                 :            :     }
     627                 :            : 
     628                 :        230 :   elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
     629         [ -  + ]:        230 :   if (elfnew == NULL)
     630                 :            :     {
     631                 :          0 :       error (0, 0, "Couldn't open new ELF %s for writing: %s",
     632                 :            :              fnew, elf_errmsg (-1));
     633                 :          0 :       goto cleanup;
     634                 :            :     }
     635                 :            : 
     636                 :            :   /* Create the new ELF header and copy over all the data.  */
     637         [ -  + ]:        230 :   if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
     638                 :            :     {
     639                 :          0 :       error (0, 0, "Couldn't create new ehdr: %s", elf_errmsg (-1));
     640                 :          0 :       goto cleanup;
     641                 :            :     }
     642                 :            : 
     643                 :        230 :   GElf_Ehdr newehdr;
     644         [ -  + ]:        230 :   if (gelf_getehdr (elfnew, &newehdr) == NULL)
     645                 :            :     {
     646                 :          0 :       error (0, 0, "Couldn't get new ehdr: %s", elf_errmsg (-1));
     647                 :          0 :       goto cleanup;
     648                 :            :     }
     649                 :            : 
     650                 :        230 :   newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
     651                 :        230 :   newehdr.e_type = ehdr.e_type;
     652                 :        230 :   newehdr.e_machine = ehdr.e_machine;
     653                 :        230 :   newehdr.e_version = ehdr.e_version;
     654                 :        230 :   newehdr.e_entry = ehdr.e_entry;
     655                 :        230 :   newehdr.e_flags = ehdr.e_flags;
     656                 :            : 
     657         [ -  + ]:        230 :   if (gelf_update_ehdr (elfnew, &newehdr) == 0)
     658                 :            :     {
     659                 :          0 :       error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
     660                 :          0 :       goto cleanup;
     661                 :            :     }
     662                 :            : 
     663                 :            :   /* Copy over the phdrs as is.  */
     664         [ +  + ]:        230 :   if (phnum != 0)
     665                 :            :     {
     666         [ -  + ]:        213 :       if (gelf_newphdr (elfnew, phnum) == 0)
     667                 :            :         {
     668                 :          0 :           error (0, 0, "Couldn't create phdrs: %s", elf_errmsg (-1));
     669                 :          0 :           goto cleanup;
     670                 :            :         }
     671                 :            : 
     672         [ +  + ]:       1008 :       for (size_t cnt = 0; cnt < phnum; ++cnt)
     673                 :            :         {
     674                 :        795 :           GElf_Phdr phdr_mem;
     675                 :        795 :           GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
     676         [ -  + ]:        795 :           if (phdr == NULL)
     677                 :            :             {
     678                 :          0 :               error (0, 0, "Couldn't get phdr %zd: %s", cnt, elf_errmsg (-1));
     679                 :          0 :               goto cleanup;
     680                 :            :             }
     681         [ -  + ]:        795 :           if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
     682                 :            :             {
     683                 :          0 :               error (0, 0, "Couldn't create phdr %zd: %s", cnt,
     684                 :            :                      elf_errmsg (-1));
     685                 :          0 :               goto cleanup;
     686                 :            :             }
     687                 :            :         }
     688                 :            :     }
     689                 :            : 
     690                 :            :   /* Possibly add a 'z' and zero terminator.  */
     691         [ +  + ]:        230 :   if (maxnamelen > 0)
     692                 :         98 :     snamebuf = xmalloc (maxnamelen + 2);
     693                 :            : 
     694                 :            :   /* We might want to read/adjust the section header strings and
     695                 :            :      symbol tables.  If so, and those sections are to be compressed
     696                 :            :      then we will have to decompress it during the collection pass and
     697                 :            :      compress it again in the fixup pass.  Don't compress unnecessary
     698                 :            :      and keep track of whether or not to compress them (later in the
     699                 :            :      fixup pass).  Also record the original size, so we can report the
     700                 :            :      difference later when we do compress.  */
     701                 :        230 :   enum ch_type shstrtab_compressed = UNSET;
     702                 :        230 :   size_t shstrtab_size = 0;
     703                 :        230 :   char *shstrtab_name = NULL;
     704                 :        230 :   char *shstrtab_newname = NULL;
     705                 :        230 :   enum ch_type symtab_compressed = UNSET;
     706                 :        230 :   size_t symtab_size = 0;
     707                 :        230 :   char *symtab_name = NULL;
     708                 :        230 :   char *symtab_newname = NULL;
     709                 :            : 
     710                 :            :   /* Collection pass.  Copy over the sections, (de)compresses matching
     711                 :            :      sections, collect names of sections and symbol table if
     712                 :            :      necessary.  */
     713                 :        230 :   scn = NULL;
     714         [ +  + ]:       4787 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     715                 :            :     {
     716                 :       4557 :       size_t ndx = elf_ndxscn (scn);
     717         [ -  + ]:       4557 :       assert (ndx < shnum);
     718                 :            : 
     719                 :            :       /* (de)compress if section matched.  */
     720                 :       4557 :       char *sname = NULL;
     721                 :       4557 :       char *newname = NULL;
     722         [ +  + ]:       4557 :       if (get_section (sections, ndx))
     723                 :            :         {
     724                 :       1188 :           GElf_Shdr shdr_mem;
     725                 :       1188 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     726         [ -  + ]:       1188 :           if (shdr == NULL)
     727                 :            :             {
     728                 :          0 :               error (0, 0, "Couldn't get shdr for section %zd", ndx);
     729                 :          0 :               goto cleanup;
     730                 :            :             }
     731                 :            : 
     732                 :       1188 :           uint64_t size = shdr->sh_size;
     733                 :       1188 :           sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
     734         [ -  + ]:       1188 :           if (sname == NULL)
     735                 :            :             {
     736                 :          0 :               error (0, 0, "Couldn't get name for section %zd", ndx);
     737                 :          0 :               goto cleanup;
     738                 :            :             }
     739                 :            : 
     740                 :            :           /* strdup sname, the shdrstrndx section itself might be
     741                 :            :              (de)compressed, invalidating the string pointers.  */
     742                 :       1188 :           sname = xstrdup (sname);
     743                 :            : 
     744                 :            : 
     745                 :            :           /* Detect source compression that is how is the section compressed
     746                 :            :              now.  */
     747                 :       1188 :           enum ch_type schtype = get_section_chtype (scn, shdr, sname, ndx);
     748         [ -  + ]:       1188 :           if (schtype == UNSET)
     749                 :          0 :             goto cleanup;
     750                 :            : 
     751                 :            :           /* We might want to decompress (and rename), but not
     752                 :            :              compress during this pass since we might need the section
     753                 :            :              data in later passes.  Skip those sections for now and
     754                 :            :              compress them in the fixup pass.  */
     755                 :       2376 :           bool skip_compress_section = (adjust_names
     756   [ +  +  +  - ]:       1188 :                                         && (ndx == shdrstrndx
     757         [ +  - ]:        513 :                                             || ndx == symtabndx));
     758                 :            : 
     759   [ +  +  +  - ]:       1188 :           switch (type)
     760                 :            :             {
     761                 :        373 :             case NONE:
     762         [ +  + ]:        373 :               if (schtype != NONE)
     763                 :            :                 {
     764         [ +  + ]:        244 :                   if (schtype == ZLIB_GNU)
     765                 :            :                     {
     766                 :        122 :                       snamebuf[0] = '.';
     767                 :        122 :                       strcpy (&snamebuf[1], &sname[2]);
     768                 :        122 :                       newname = snamebuf;
     769                 :            :                     }
     770         [ -  + ]:        244 :                   if (compress_section (scn, size, sname, NULL, ndx,
     771                 :            :                                         schtype, NONE, verbose > 0) < 0)
     772                 :          0 :                     goto cleanup;
     773                 :            :                 }
     774         [ +  + ]:        129 :               else if (verbose > 0)
     775                 :        122 :                 printf ("[%zd] %s already decompressed\n", ndx, sname);
     776                 :            :               break;
     777                 :            : 
     778                 :        359 :             case ZLIB_GNU:
     779         [ +  - ]:        359 :               if (startswith (sname, ".debug"))
     780                 :            :                 {
     781         [ +  + ]:        359 :                   if (schtype == ZLIB || schtype == ZSTD)
     782                 :            :                     {
     783                 :            :                       /* First decompress to recompress GNU style.
     784                 :            :                          Don't report even when verbose.  */
     785         [ -  + ]:         92 :                       if (compress_section (scn, size, sname, NULL, ndx,
     786                 :            :                                             schtype, NONE, false) < 0)
     787                 :          0 :                         goto cleanup;
     788                 :            :                     }
     789                 :            : 
     790                 :        359 :                   snamebuf[0] = '.';
     791                 :        359 :                   snamebuf[1] = 'z';
     792         [ -  + ]:        359 :                   strcpy (&snamebuf[2], &sname[1]);
     793                 :        359 :                   newname = snamebuf;
     794                 :            : 
     795         [ -  + ]:        359 :                   if (skip_compress_section)
     796                 :            :                     {
     797         [ #  # ]:          0 :                       if (ndx == shdrstrndx)
     798                 :            :                         {
     799                 :          0 :                           shstrtab_size = size;
     800                 :          0 :                           shstrtab_compressed = ZLIB_GNU;
     801                 :          0 :                           if (shstrtab_name != NULL
     802         [ #  # ]:          0 :                               || shstrtab_newname != NULL)
     803                 :            :                             {
     804                 :          0 :                               error (0, 0, "Internal error,"
     805                 :            :                                            " shstrtab_name already set,"
     806                 :            :                                            " while handling section [%zd] %s",
     807                 :            :                                      ndx, sname);
     808                 :          0 :                               goto cleanup;
     809                 :            :                             }
     810                 :          0 :                           shstrtab_name = xstrdup (sname);
     811                 :          0 :                           shstrtab_newname = xstrdup (newname);
     812                 :            :                         }
     813                 :            :                       else
     814                 :            :                         {
     815                 :          0 :                           symtab_size = size;
     816                 :          0 :                           symtab_compressed = ZLIB_GNU;
     817                 :          0 :                           symtab_name = xstrdup (sname);
     818                 :          0 :                           symtab_newname = xstrdup (newname);
     819                 :            :                         }
     820                 :            :                     }
     821                 :            :                   else
     822                 :            :                     {
     823                 :        359 :                       int result = compress_section (scn, size, sname, newname,
     824                 :            :                                                      ndx, NONE, type,
     825                 :            :                                                      verbose > 0);
     826         [ -  + ]:        359 :                       if (result < 0)
     827                 :          0 :                         goto cleanup;
     828                 :            : 
     829         [ +  + ]:        359 :                       if (result == 0)
     830                 :         48 :                         newname = NULL;
     831                 :            :                     }
     832                 :            :                 }
     833         [ #  # ]:          0 :               else if (verbose >= 0)
     834                 :            :                 {
     835         [ #  # ]:          0 :                   if (schtype == ZLIB_GNU)
     836                 :          0 :                     printf ("[%zd] %s unchanged, already GNU compressed\n",
     837                 :            :                             ndx, sname);
     838                 :            :                   else
     839                 :          0 :                     printf ("[%zd] %s cannot GNU compress section not starting with .debug\n",
     840                 :            :                             ndx, sname);
     841                 :            :                 }
     842                 :            :               break;
     843                 :            : 
     844                 :        456 :             case ZLIB:
     845                 :            :             case ZSTD:
     846         [ +  - ]:        456 :               if (schtype != type)
     847                 :            :                 {
     848         [ +  + ]:        456 :                   if (schtype != NONE)
     849                 :            :                     {
     850                 :            :                       /* Decompress first.  */
     851         [ -  + ]:         98 :                       if (compress_section (scn, size, sname, NULL, ndx,
     852                 :            :                                             schtype, NONE, false) < 0)
     853                 :          0 :                         goto cleanup;
     854                 :            : 
     855         [ -  + ]:         98 :                       if (schtype == ZLIB_GNU)
     856                 :            :                         {
     857                 :          0 :                           snamebuf[0] = '.';
     858                 :          0 :                           strcpy (&snamebuf[1], &sname[2]);
     859                 :          0 :                           newname = snamebuf;
     860                 :            :                         }
     861                 :            :                     }
     862                 :            : 
     863         [ -  + ]:        456 :                   if (skip_compress_section)
     864                 :            :                     {
     865         [ #  # ]:          0 :                       if (ndx == shdrstrndx)
     866                 :            :                         {
     867                 :          0 :                           shstrtab_size = size;
     868                 :          0 :                           shstrtab_compressed = type;
     869                 :          0 :                           if (shstrtab_name != NULL
     870         [ #  # ]:          0 :                               || shstrtab_newname != NULL)
     871                 :            :                             {
     872                 :          0 :                               error (0, 0, "Internal error,"
     873                 :            :                                            " shstrtab_name already set,"
     874                 :            :                                            " while handling section [%zd] %s",
     875                 :            :                                      ndx, sname);
     876                 :          0 :                               goto cleanup;
     877                 :            :                             }
     878                 :          0 :                           shstrtab_name = xstrdup (sname);
     879                 :          0 :                           shstrtab_newname = (newname == NULL
     880         [ #  # ]:          0 :                                               ? NULL : xstrdup (newname));
     881                 :            :                         }
     882                 :            :                       else
     883                 :            :                         {
     884                 :          0 :                           symtab_size = size;
     885                 :          0 :                           symtab_compressed = type;
     886                 :          0 :                           symtab_name = xstrdup (sname);
     887                 :          0 :                           symtab_newname = (newname == NULL
     888         [ #  # ]:          0 :                                             ? NULL : xstrdup (newname));
     889                 :            :                         }
     890                 :            :                     }
     891         [ -  + ]:        456 :                   else if (compress_section (scn, size, sname, newname, ndx,
     892                 :            :                                              NONE, type, verbose > 0) < 0)
     893                 :          0 :                     goto cleanup;
     894                 :            :                 }
     895         [ #  # ]:          0 :               else if (verbose > 0)
     896                 :          0 :                 printf ("[%zd] %s already compressed\n", ndx, sname);
     897                 :            :               break;
     898                 :            : 
     899                 :            :             case UNSET:
     900                 :            :               break;
     901                 :            :             }
     902                 :            : 
     903                 :       1188 :           free (sname);
     904                 :            :         }
     905                 :            : 
     906                 :       4557 :       Elf_Scn *newscn = elf_newscn (elfnew);
     907         [ -  + ]:       4557 :       if (newscn == NULL)
     908                 :            :         {
     909                 :          0 :           error (0, 0, "Couldn't create new section %zd", ndx);
     910                 :          0 :           goto cleanup;
     911                 :            :         }
     912                 :            : 
     913                 :       4557 :       GElf_Shdr shdr_mem;
     914                 :       4557 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     915         [ -  + ]:       4557 :       if (shdr == NULL)
     916                 :            :         {
     917                 :          0 :           error (0, 0, "Couldn't get shdr for section %zd", ndx);
     918                 :          0 :           goto cleanup;
     919                 :            :         }
     920                 :            : 
     921         [ -  + ]:       4557 :       if (gelf_update_shdr (newscn, shdr) == 0)
     922                 :            :         {
     923                 :          0 :           error (0, 0, "Couldn't update section header %zd", ndx);
     924                 :          0 :           goto cleanup;
     925                 :            :         }
     926                 :            : 
     927                 :            :       /* Except for the section header string table all data can be
     928                 :            :          copied as is.  The section header string table will be
     929                 :            :          created later and the symbol table might be fixed up if
     930                 :            :          necessary.  */
     931   [ +  +  +  + ]:       4557 :       if (! adjust_names || ndx != shdrstrndx)
     932                 :            :         {
     933                 :       4459 :           Elf_Data *data = elf_getdata (scn, NULL);
     934         [ -  + ]:       4459 :           if (data == NULL)
     935                 :            :             {
     936                 :          0 :               error (0, 0, "Couldn't get data from section %zd", ndx);
     937                 :          0 :               goto cleanup;
     938                 :            :             }
     939                 :            : 
     940                 :       4459 :           Elf_Data *newdata = elf_newdata (newscn);
     941         [ -  + ]:       4459 :           if (newdata == NULL)
     942                 :            :             {
     943                 :          0 :               error (0, 0, "Couldn't create new data for section %zd", ndx);
     944                 :          0 :               goto cleanup;
     945                 :            :             }
     946                 :            : 
     947                 :       4459 :           *newdata = *data;
     948                 :            :         }
     949                 :            : 
     950                 :            :       /* Keep track of the (new) section names.  */
     951         [ +  + ]:       4557 :       if (adjust_names)
     952                 :            :         {
     953                 :       1790 :           char *name;
     954         [ +  + ]:       1790 :           if (newname != NULL)
     955                 :            :             name = newname;
     956                 :            :           else
     957                 :            :             {
     958                 :       1357 :               name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
     959         [ -  + ]:       1357 :               if (name == NULL)
     960                 :            :                 {
     961                 :          0 :                   error (0, 0, "Couldn't get name for section [%zd]", ndx);
     962                 :          0 :                   goto cleanup;
     963                 :            :                 }
     964                 :            :             }
     965                 :            : 
     966                 :            :           /* We need to keep a copy of the name till the strtab is done.  */
     967                 :       1790 :           name = scnnames[ndx] = xstrdup (name);
     968         [ -  + ]:       1790 :           if ((scnstrents[ndx] = dwelf_strtab_add (names, name)) == NULL)
     969                 :            :             {
     970                 :          0 :               error (0, 0, "No memory to add section name string table");
     971                 :          0 :               goto cleanup;
     972                 :            :             }
     973                 :            : 
     974                 :            :           /* If the symtab shares strings then add those too.  */
     975         [ +  + ]:       1790 :           if (ndx == symtabndx)
     976                 :            :             {
     977                 :            :               /* If the section is (still) compressed we'll need to
     978                 :            :                  uncompress it first to adjust the data, then
     979                 :            :                  recompress it in the fixup pass.  */
     980         [ +  - ]:         40 :               if (symtab_compressed == UNSET)
     981                 :            :                 {
     982                 :         40 :                   size_t size = shdr->sh_size;
     983         [ -  + ]:         40 :                   if ((shdr->sh_flags == SHF_COMPRESSED) != 0)
     984                 :            :                     {
     985                 :            :                       /* Don't report the (internal) uncompression.  */
     986         [ #  # ]:          0 :                       if (compress_section (newscn, size, sname, NULL, ndx,
     987                 :            :                                             ZLIB, NONE, false) < 0)
     988                 :          0 :                         goto cleanup;
     989                 :            : 
     990                 :            :                       symtab_size = size;
     991                 :            :                       symtab_compressed = ZLIB;
     992                 :            :                     }
     993         [ -  + ]:         40 :                   else if (startswith (name, ".zdebug"))
     994                 :            :                     {
     995                 :            :                       /* Don't report the (internal) uncompression.  */
     996         [ #  # ]:          0 :                       if (compress_section (newscn, size, sname, NULL, ndx,
     997                 :            :                                             ZLIB_GNU, NONE, false) < 0)
     998                 :          0 :                         goto cleanup;
     999                 :            : 
    1000                 :            :                       symtab_size = size;
    1001                 :            :                       symtab_compressed = ZLIB_GNU;
    1002                 :            :                     }
    1003                 :            :                 }
    1004                 :            : 
    1005                 :         40 :               Elf_Data *symd = elf_getdata (newscn, NULL);
    1006         [ -  + ]:         40 :               if (symd == NULL)
    1007                 :            :                 {
    1008                 :          0 :                   error (0, 0, "Couldn't get symtab data for section [%zd] %s",
    1009                 :            :                          ndx, name);
    1010                 :          0 :                   goto cleanup;
    1011                 :            :                 }
    1012                 :         40 :               size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
    1013                 :         40 :               size_t syms = symd->d_size / elsize;
    1014         [ -  + ]:         40 :               if (symstrents != NULL)
    1015                 :            :                 {
    1016                 :          0 :                   error (0, 0, "Internal error, symstrents already set,"
    1017                 :            :                          " while handling section [%zd] %s", ndx, name);
    1018                 :          0 :                   goto cleanup;
    1019                 :            :                 }
    1020                 :         40 :               symstrents = xmalloc (syms * sizeof (Dwelf_Strent *));
    1021         [ +  + ]:       2209 :               for (size_t i = 0; i < syms; i++)
    1022                 :            :                 {
    1023                 :       2169 :                   GElf_Sym sym_mem;
    1024                 :       2169 :                   GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
    1025         [ -  + ]:       2169 :                   if (sym == NULL)
    1026                 :            :                     {
    1027                 :          0 :                       error (0, 0, "Couldn't get symbol %zd", i);
    1028                 :          0 :                       goto cleanup;
    1029                 :            :                     }
    1030         [ +  + ]:       2169 :                   if (sym->st_name != 0)
    1031                 :            :                     {
    1032                 :            :                       /* Note we take the name from the original ELF,
    1033                 :            :                          since the new one will not have setup the
    1034                 :            :                          strtab yet.  */
    1035                 :       1561 :                       const char *symname = elf_strptr (elf, shdrstrndx,
    1036                 :            :                                                         sym->st_name);
    1037         [ -  + ]:       1561 :                       if (symname == NULL)
    1038                 :            :                         {
    1039                 :          0 :                           error (0, 0, "Couldn't get symbol %zd name", i);
    1040                 :          0 :                           goto cleanup;
    1041                 :            :                         }
    1042                 :       1561 :                       symstrents[i] = dwelf_strtab_add (names, symname);
    1043         [ -  + ]:       1561 :                       if (symstrents[i] == NULL)
    1044                 :            :                         {
    1045                 :          0 :                           error (0, 0, "No memory to add to symbol name");
    1046                 :          0 :                           goto cleanup;
    1047                 :            :                         }
    1048                 :            :                     }
    1049                 :            :                 }
    1050                 :            :             }
    1051                 :            :         }
    1052                 :            :     }
    1053                 :            : 
    1054         [ +  + ]:        230 :   if (adjust_names)
    1055                 :            :     {
    1056                 :            :       /* We got all needed strings, put the new data in the shstrtab.  */
    1057         [ +  + ]:         98 :       if (verbose > 0)
    1058                 :         80 :         printf ("[%zd] Updating section string table\n", shdrstrndx);
    1059                 :            : 
    1060                 :         98 :       scn = elf_getscn (elfnew, shdrstrndx);
    1061         [ -  + ]:         98 :       if (scn == NULL)
    1062                 :            :         {
    1063                 :          0 :           error (0, 0, "Couldn't get new section header string table [%zd]",
    1064                 :            :                  shdrstrndx);
    1065                 :          0 :           goto cleanup;
    1066                 :            :         }
    1067                 :            : 
    1068                 :         98 :       Elf_Data *data = elf_newdata (scn);
    1069         [ -  + ]:         98 :       if (data == NULL)
    1070                 :            :         {
    1071                 :          0 :           error (0, 0, "Couldn't create new section header string table data");
    1072                 :          0 :           goto cleanup;
    1073                 :            :         }
    1074         [ -  + ]:         98 :       if (dwelf_strtab_finalize (names, data) == NULL)
    1075                 :            :         {
    1076                 :          0 :           error (0, 0, "Not enough memory to create string table");
    1077                 :          0 :           goto cleanup;
    1078                 :            :         }
    1079                 :         98 :       namesbuf = data->d_buf;
    1080                 :            : 
    1081                 :         98 :       GElf_Shdr shdr_mem;
    1082                 :         98 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1083         [ -  + ]:         98 :       if (shdr == NULL)
    1084                 :            :         {
    1085                 :          0 :           error (0, 0, "Couldn't get shdr for new section strings %zd",
    1086                 :            :                  shdrstrndx);
    1087                 :          0 :           goto cleanup;
    1088                 :            :         }
    1089                 :            : 
    1090                 :            :       /* Note that we also might have to compress and possibly set
    1091                 :            :          sh_off below */
    1092                 :         98 :       shdr->sh_name = dwelf_strent_off (scnstrents[shdrstrndx]);
    1093                 :         98 :       shdr->sh_type = SHT_STRTAB;
    1094                 :         98 :       shdr->sh_flags = 0;
    1095                 :         98 :       shdr->sh_addr = 0;
    1096                 :         98 :       shdr->sh_offset = 0;
    1097                 :         98 :       shdr->sh_size = data->d_size;
    1098                 :         98 :       shdr->sh_link = SHN_UNDEF;
    1099                 :         98 :       shdr->sh_info = SHN_UNDEF;
    1100                 :         98 :       shdr->sh_addralign = 1;
    1101                 :         98 :       shdr->sh_entsize = 0;
    1102                 :            : 
    1103         [ -  + ]:         98 :       if (gelf_update_shdr (scn, shdr) == 0)
    1104                 :            :         {
    1105                 :          0 :           error (0, 0, "Couldn't update new section strings [%zd]",
    1106                 :            :                  shdrstrndx);
    1107                 :          0 :           goto cleanup;
    1108                 :            :         }
    1109                 :            : 
    1110                 :            :       /* We might have to compress the data if the user asked us to,
    1111                 :            :          or if the section was already compressed (and the user didn't
    1112                 :            :          ask for decompression).  Note somewhat identical code for
    1113                 :            :          symtab below.  */
    1114         [ +  - ]:         98 :       if (shstrtab_compressed == UNSET)
    1115                 :            :         {
    1116                 :            :           /* The user didn't ask for compression, but maybe it was
    1117                 :            :              compressed in the original ELF file.  */
    1118                 :         98 :           Elf_Scn *oldscn = elf_getscn (elf, shdrstrndx);
    1119         [ -  + ]:         98 :           if (oldscn == NULL)
    1120                 :            :             {
    1121                 :          0 :               error (0, 0, "Couldn't get section header string table [%zd]",
    1122                 :            :                      shdrstrndx);
    1123                 :          0 :               goto cleanup;
    1124                 :            :             }
    1125                 :            : 
    1126                 :         98 :           shdr = gelf_getshdr (oldscn, &shdr_mem);
    1127         [ -  + ]:         98 :           if (shdr == NULL)
    1128                 :            :             {
    1129                 :          0 :               error (0, 0, "Couldn't get shdr for old section strings [%zd]",
    1130                 :            :                      shdrstrndx);
    1131                 :          0 :               goto cleanup;
    1132                 :            :             }
    1133                 :            : 
    1134                 :         98 :           shstrtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
    1135         [ -  + ]:         98 :           if (shstrtab_name == NULL)
    1136                 :            :             {
    1137                 :          0 :               error (0, 0, "Couldn't get name for old section strings [%zd]",
    1138                 :            :                      shdrstrndx);
    1139                 :          0 :               goto cleanup;
    1140                 :            :             }
    1141                 :            : 
    1142                 :         98 :           shstrtab_size = shdr->sh_size;
    1143         [ +  - ]:         98 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1144                 :            :             shstrtab_compressed = ZLIB;
    1145         [ -  + ]:         98 :           else if (startswith (shstrtab_name, ".zdebug"))
    1146                 :          0 :             shstrtab_compressed = ZLIB_GNU;
    1147                 :            :         }
    1148                 :            : 
    1149                 :            :       /* Should we (re)compress?  */
    1150         [ -  + ]:         98 :       if (shstrtab_compressed != UNSET)
    1151                 :            :         {
    1152         [ #  # ]:          0 :           if (compress_section (scn, shstrtab_size, shstrtab_name,
    1153                 :            :                                 shstrtab_newname, shdrstrndx,
    1154                 :            :                                 NONE, shstrtab_compressed,
    1155                 :            :                                 verbose > 0) < 0)
    1156                 :          0 :             goto cleanup;
    1157                 :            :         }
    1158                 :            :     }
    1159                 :            : 
    1160                 :            :   /* Make sure to re-get the new ehdr.  Adding phdrs and shdrs will
    1161                 :            :      have changed it.  */
    1162         [ -  + ]:        230 :   if (gelf_getehdr (elfnew, &newehdr) == NULL)
    1163                 :            :     {
    1164                 :          0 :       error (0, 0, "Couldn't re-get new ehdr: %s", elf_errmsg (-1));
    1165                 :          0 :       goto cleanup;
    1166                 :            :     }
    1167                 :            : 
    1168                 :            :   /* Set this after the sections have been created, otherwise section
    1169                 :            :      zero might not exist yet.  */
    1170         [ -  + ]:        230 :   if (setshdrstrndx (elfnew, &newehdr, shdrstrndx) != 0)
    1171                 :            :     {
    1172                 :          0 :       error (0, 0, "Couldn't set new shdrstrndx: %s", elf_errmsg (-1));
    1173                 :          0 :       goto cleanup;
    1174                 :            :     }
    1175                 :            : 
    1176                 :            :   /* Fixup pass.  Adjust string table references, symbol table and
    1177                 :            :      layout if necessary.  */
    1178         [ +  + ]:        230 :   if (layout || adjust_names)
    1179                 :            :     {
    1180                 :            :       scn = NULL;
    1181         [ +  + ]:       4515 :       while ((scn = elf_nextscn (elfnew, scn)) != NULL)
    1182                 :            :         {
    1183                 :       4291 :           size_t ndx = elf_ndxscn (scn);
    1184                 :            : 
    1185                 :       4291 :           GElf_Shdr shdr_mem;
    1186                 :       4291 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1187         [ -  + ]:       4291 :           if (shdr == NULL)
    1188                 :            :             {
    1189                 :          0 :               error (0, 0, "Couldn't get shdr for section %zd", ndx);
    1190                 :          0 :               goto cleanup;
    1191                 :            :             }
    1192                 :            : 
    1193                 :            :           /* Keep the offset of allocated sections so they are at the
    1194                 :            :              same place in the file. Add (possibly changed)
    1195                 :            :              unallocated ones after the allocated ones.  */
    1196         [ +  + ]:       4291 :           if ((shdr->sh_flags & SHF_ALLOC) == 0)
    1197                 :            :             {
    1198                 :            :               /* Zero means one.  No alignment constraints.  */
    1199                 :       1997 :               size_t addralign = shdr->sh_addralign ?: 1;
    1200                 :       1997 :               last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
    1201                 :       1997 :               shdr->sh_offset = last_offset;
    1202         [ +  + ]:       1997 :               if (shdr->sh_type != SHT_NOBITS)
    1203                 :       1990 :                 last_offset += shdr->sh_size;
    1204                 :            :             }
    1205                 :            : 
    1206         [ +  + ]:       4291 :           if (adjust_names)
    1207                 :       1790 :             shdr->sh_name = dwelf_strent_off (scnstrents[ndx]);
    1208                 :            : 
    1209         [ -  + ]:       4291 :           if (gelf_update_shdr (scn, shdr) == 0)
    1210                 :            :             {
    1211                 :          0 :               error (0, 0, "Couldn't update section header %zd", ndx);
    1212                 :          0 :               goto cleanup;
    1213                 :            :             }
    1214                 :            : 
    1215         [ +  + ]:       4291 :           if (adjust_names && ndx == symtabndx)
    1216                 :            :             {
    1217         [ +  - ]:         40 :               if (verbose > 0)
    1218                 :         40 :                 printf ("[%zd] Updating symbol table\n", symtabndx);
    1219                 :            : 
    1220                 :         40 :               Elf_Data *symd = elf_getdata (scn, NULL);
    1221         [ -  + ]:         40 :               if (symd == NULL)
    1222                 :            :                 {
    1223                 :          0 :                   error (0, 0, "Couldn't get new symtab data section [%zd]",
    1224                 :            :                          ndx);
    1225                 :          0 :                   goto cleanup;
    1226                 :            :                 }
    1227                 :         40 :               size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
    1228                 :         40 :               size_t syms = symd->d_size / elsize;
    1229         [ +  + ]:       2209 :               for (size_t i = 0; i < syms; i++)
    1230                 :            :                 {
    1231                 :       2169 :                   GElf_Sym sym_mem;
    1232                 :       2169 :                   GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
    1233         [ -  + ]:       2169 :                   if (sym == NULL)
    1234                 :            :                     {
    1235                 :          0 :                       error (0, 0, "2 Couldn't get symbol %zd", i);
    1236                 :          0 :                       goto cleanup;
    1237                 :            :                     }
    1238                 :            : 
    1239         [ +  + ]:       2169 :                   if (sym->st_name != 0)
    1240                 :            :                     {
    1241                 :       1561 :                       sym->st_name = dwelf_strent_off (symstrents[i]);
    1242                 :            : 
    1243         [ -  + ]:       1561 :                       if (gelf_update_sym (symd, i, sym) == 0)
    1244                 :            :                         {
    1245                 :          0 :                           error (0, 0, "Couldn't update symbol %zd", i);
    1246                 :          0 :                           goto cleanup;
    1247                 :            :                         }
    1248                 :            :                     }
    1249                 :            :                 }
    1250                 :            : 
    1251                 :            :               /* We might have to compress the data if the user asked
    1252                 :            :                  us to, or if the section was already compressed (and
    1253                 :            :                  the user didn't ask for decompression).  Note
    1254                 :            :                  somewhat identical code for shstrtab above.  */
    1255         [ +  - ]:         40 :               if (symtab_compressed == UNSET)
    1256                 :            :                 {
    1257                 :            :                   /* The user didn't ask for compression, but maybe it was
    1258                 :            :                      compressed in the original ELF file.  */
    1259                 :         40 :                   Elf_Scn *oldscn = elf_getscn (elf, symtabndx);
    1260         [ -  + ]:         40 :                   if (oldscn == NULL)
    1261                 :            :                     {
    1262                 :          0 :                       error (0, 0, "Couldn't get symbol table [%zd]",
    1263                 :            :                              symtabndx);
    1264                 :          0 :                       goto cleanup;
    1265                 :            :                     }
    1266                 :            : 
    1267                 :         40 :                   shdr = gelf_getshdr (oldscn, &shdr_mem);
    1268         [ -  + ]:         40 :                   if (shdr == NULL)
    1269                 :            :                     {
    1270                 :          0 :                       error (0, 0, "Couldn't get old symbol table shdr [%zd]",
    1271                 :            :                              symtabndx);
    1272                 :          0 :                       goto cleanup;
    1273                 :            :                     }
    1274                 :            : 
    1275                 :         40 :                   symtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
    1276         [ -  + ]:         40 :                   if (symtab_name == NULL)
    1277                 :            :                     {
    1278                 :          0 :                       error (0, 0, "Couldn't get old symbol table name [%zd]",
    1279                 :            :                              symtabndx);
    1280                 :          0 :                       goto cleanup;
    1281                 :            :                     }
    1282                 :            : 
    1283                 :         40 :                   symtab_size = shdr->sh_size;
    1284         [ +  - ]:         40 :                   if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1285                 :            :                     symtab_compressed = ZLIB;
    1286         [ -  + ]:         40 :                   else if (startswith (symtab_name, ".zdebug"))
    1287                 :          0 :                     symtab_compressed = ZLIB_GNU;
    1288                 :            :                 }
    1289                 :            : 
    1290                 :            :               /* Should we (re)compress?  */
    1291         [ -  + ]:         40 :               if (symtab_compressed != UNSET)
    1292                 :            :                 {
    1293         [ #  # ]:          0 :                   if (compress_section (scn, symtab_size, symtab_name,
    1294                 :            :                                         symtab_newname, symtabndx,
    1295                 :            :                                         NONE, symtab_compressed,
    1296                 :            :                                         verbose > 0) < 0)
    1297                 :          0 :                     goto cleanup;
    1298                 :            :                 }
    1299                 :            :             }
    1300                 :            :         }
    1301                 :            :     }
    1302                 :            : 
    1303                 :            :   /* If we have phdrs we want elf_update to layout the SHF_ALLOC
    1304                 :            :      sections precisely as in the original file.  In that case we are
    1305                 :            :      also responsible for setting phoff and shoff */
    1306         [ +  + ]:        230 :   if (layout)
    1307                 :            :     {
    1308         [ -  + ]:        213 :       if (gelf_getehdr (elfnew, &newehdr) == NULL)
    1309                 :            :         {
    1310                 :          0 :           error (0, 0, "Couldn't get ehdr: %s", elf_errmsg (-1));
    1311                 :          0 :           goto cleanup;
    1312                 :            :         }
    1313                 :            : 
    1314                 :            :       /* Position the shdrs after the last (unallocated) section.  */
    1315                 :        213 :       const size_t offsize = gelf_fsize (elfnew, ELF_T_OFF, 1, EV_CURRENT);
    1316                 :        213 :       newehdr.e_shoff = ((last_offset + offsize - 1)
    1317                 :        213 :                          & ~((GElf_Off) (offsize - 1)));
    1318                 :            : 
    1319                 :            :       /* The phdrs go in the same place as in the original file.
    1320                 :            :          Normally right after the ELF header.  */
    1321                 :        213 :       newehdr.e_phoff = ehdr.e_phoff;
    1322                 :            : 
    1323         [ -  + ]:        213 :       if (gelf_update_ehdr (elfnew, &newehdr) == 0)
    1324                 :            :         {
    1325                 :          0 :           error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
    1326                 :          0 :           goto cleanup;
    1327                 :            :         }
    1328                 :            :     }
    1329                 :            : 
    1330         [ +  + ]:        230 :   elf_flagelf (elfnew, ELF_C_SET, ((layout ? ELF_F_LAYOUT : 0)
    1331         [ +  - ]:        460 :                                    | (permissive ? ELF_F_PERMISSIVE : 0)));
    1332                 :            : 
    1333         [ -  + ]:        230 :   if (elf_update (elfnew, ELF_C_WRITE) < 0)
    1334                 :            :     {
    1335                 :          0 :       error (0, 0, "Couldn't write %s: %s", fnew, elf_errmsg (-1));
    1336                 :          0 :       goto cleanup;
    1337                 :            :     }
    1338                 :            : 
    1339                 :        230 :   elf_end (elfnew);
    1340                 :        230 :   elfnew = NULL;
    1341                 :            : 
    1342                 :            :   /* Try to match mode and owner.group of the original file.
    1343                 :            :      Note to set suid bits we have to make sure the owner is setup
    1344                 :            :      correctly first. Otherwise fchmod will drop them silently
    1345                 :            :      or fchown may clear them.  */
    1346         [ -  + ]:        230 :   if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
    1347         [ #  # ]:          0 :     if (verbose >= 0)
    1348                 :          0 :       error (0, errno, "Couldn't fchown %s", fnew);
    1349         [ -  + ]:        230 :   if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
    1350         [ #  # ]:          0 :     if (verbose >= 0)
    1351                 :          0 :       error (0, errno, "Couldn't fchmod %s", fnew);
    1352                 :            : 
    1353                 :            :   /* Finally replace the old file with the new file.  */
    1354         [ +  + ]:        230 :   if (foutput == NULL)
    1355         [ -  + ]:         26 :     if (rename (fnew, fname) != 0)
    1356                 :            :       {
    1357                 :          0 :         error (0, errno, "Couldn't rename %s to %s", fnew, fname);
    1358                 :          0 :         goto cleanup;
    1359                 :            :       }
    1360                 :            : 
    1361                 :            :   /* We are finally done with the new file, don't unlink it now.  */
    1362                 :        230 :   free (fnew);
    1363                 :        230 :   fnew = NULL;
    1364                 :        230 :   res = 0;
    1365                 :            : 
    1366                 :        230 : cleanup:
    1367                 :        230 :   elf_end (elf);
    1368                 :        230 :   close (fd);
    1369                 :            : 
    1370                 :        230 :   elf_end (elfnew);
    1371                 :        230 :   close (fdnew);
    1372                 :            : 
    1373         [ -  + ]:        230 :   if (fnew != NULL)
    1374                 :            :     {
    1375                 :          0 :       unlink (fnew);
    1376                 :          0 :       free (fnew);
    1377                 :          0 :       fnew = NULL;
    1378                 :            :     }
    1379                 :            : 
    1380                 :        230 :   free (snamebuf);
    1381         [ +  + ]:        230 :   if (names != NULL)
    1382                 :            :     {
    1383                 :         98 :       dwelf_strtab_free (names);
    1384                 :         98 :       free (scnstrents);
    1385                 :         98 :       free (symstrents);
    1386                 :         98 :       free (namesbuf);
    1387         [ +  - ]:         98 :       if (scnnames != NULL)
    1388                 :            :         {
    1389         [ +  + ]:       1986 :           for (size_t n = 0; n < shnum; n++)
    1390                 :       1888 :             free (scnnames[n]);
    1391                 :         98 :           free (scnnames);
    1392                 :            :         }
    1393                 :            :     }
    1394                 :            : 
    1395                 :        230 :   free (sections);
    1396                 :        230 :   return res;
    1397                 :            : }
    1398                 :            : 
    1399                 :            : int
    1400                 :        214 : main (int argc, char **argv)
    1401                 :            : {
    1402                 :        214 :   const struct argp_option options[] =
    1403                 :            :     {
    1404                 :            :       { "output", 'o', "FILE", 0,
    1405                 :            :         N_("Place (de)compressed output into FILE"),
    1406                 :            :         0 },
    1407                 :            :       { "type", 't', "TYPE", 0,
    1408                 :            :         N_("What type of compression to apply. TYPE can be 'none' (decompress), 'zlib' (ELF ZLIB compression, the default, 'zlib-gabi' is an alias), "
    1409                 :            :            "'zlib-gnu' (.zdebug GNU style compression, 'gnu' is an alias) or 'zstd' (ELF ZSTD compression)"),
    1410                 :            :         0 },
    1411                 :            :       { "name", 'n', "SECTION", 0,
    1412                 :            :         N_("SECTION name to (de)compress, SECTION is an extended wildcard pattern (defaults to '.?(z)debug*')"),
    1413                 :            :         0 },
    1414                 :            :       { "verbose", 'v', NULL, 0,
    1415                 :            :         N_("Print a message for each section being (de)compressed"),
    1416                 :            :         0 },
    1417                 :            :       { "force", 'f', NULL, 0,
    1418                 :            :         N_("Force compression of section even if it would become larger or update/rewrite the file even if no section would be (de)compressed"),
    1419                 :            :         0 },
    1420                 :            :       { "permissive", 'p', NULL, 0,
    1421                 :            :         N_("Relax a few rules to handle slightly broken ELF files"),
    1422                 :            :         0 },
    1423                 :            :       { "quiet", 'q', NULL, 0,
    1424                 :            :         N_("Be silent when a section cannot be compressed"),
    1425                 :            :         0 },
    1426                 :            :       { NULL, 0, NULL, 0, NULL, 0 }
    1427                 :            :     };
    1428                 :            : 
    1429                 :        214 :   const struct argp argp =
    1430                 :            :     {
    1431                 :            :       .options = options,
    1432                 :            :       .parser = parse_opt,
    1433                 :            :       .args_doc = N_("FILE..."),
    1434                 :            :       .doc = N_("Compress or decompress sections in an ELF file.")
    1435                 :            :     };
    1436                 :            : 
    1437                 :        214 :   int remaining;
    1438         [ +  - ]:        214 :   if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
    1439                 :            :     return EXIT_FAILURE;
    1440                 :            : 
    1441                 :            :   /* Should already be handled by ARGP_KEY_NO_ARGS case above,
    1442                 :            :      just sanity check.  */
    1443         [ -  + ]:        214 :   if (remaining >= argc)
    1444                 :          0 :     error_exit (0, N_("No input file given"));
    1445                 :            : 
    1446                 :            :   /* Likewise for the ARGP_KEY_ARGS case above, an extra sanity check.  */
    1447   [ +  +  -  + ]:        214 :   if (foutput != NULL && remaining + 1 < argc)
    1448                 :          0 :     error_exit (0, N_("Only one input file allowed together with '-o'"));
    1449                 :            : 
    1450                 :        214 :   elf_version (EV_CURRENT);
    1451                 :            : 
    1452                 :            :   /* Process all the remaining files.  */
    1453                 :        214 :   int result = 0;
    1454                 :        230 :   do
    1455                 :        230 :     result |= process_file (argv[remaining]);
    1456         [ +  + ]:        230 :   while (++remaining < argc);
    1457                 :            : 
    1458                 :        214 :   free_patterns ();
    1459                 :        214 :   return result;
    1460                 :            : }

Generated by: LCOV version 1.14