LCOV - code coverage report
Current view: top level - src - elfcompress.c (source / functions) Hit Total Coverage
Test: elfutils-0.189 Lines: 432 651 66.4 %
Date: 2023-08-29 13:46:25 Functions: 9 9 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 274 439 62.4 %

           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                 :       4591 : section_name_matches (const char *name)
     180                 :            : {
     181                 :       4591 :   struct section_pattern *pattern = patterns;
     182         [ +  + ]:       7984 :   while (pattern != NULL)
     183                 :            :     {
     184         [ +  + ]:       4591 :       if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
     185                 :            :         return true;
     186                 :       3393 :       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                 :            :     return -1;
     211                 :            : 
     212                 :            :   return 0;
     213                 :            : }
     214                 :            : 
     215                 :            : static int
     216                 :       1258 : 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         [ -  + ]:       1258 :   assert (schtype == NONE || dchtype == NONE);
     223                 :       1258 :   bool compress = dchtype != NONE;
     224                 :            : 
     225                 :       1258 :   int res;
     226   [ +  +  +  + ]:       1258 :   unsigned int flags = compress && force ? ELF_CHF_FORCE : 0;
     227         [ +  + ]:       1258 :   if (schtype == ZLIB_GNU || dchtype == ZLIB_GNU)
     228                 :        481 :     res = elf_compress_gnu (scn, compress ? 1 : 0, flags);
     229                 :            :   else
     230                 :        777 :     res = elf_compress (scn, dchtype, flags);
     231                 :            : 
     232         [ -  + ]:       1258 :   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         [ +  + ]:       1258 :       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         [ +  + ]:       1258 :       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                 :       1068 : set_section (unsigned int *sections, size_t ndx)
     272                 :            : {
     273                 :       1068 :   sections[ndx / WORD_BITS] |= (1U << (ndx % WORD_BITS));
     274                 :            : }
     275                 :            : 
     276                 :            : static bool
     277                 :       4591 : get_section (unsigned int *sections, size_t ndx)
     278                 :            : {
     279                 :       4591 :   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                 :       2266 : get_section_chtype (Elf_Scn *scn, GElf_Shdr *shdr, const char *sname,
     296                 :            :                     size_t ndx)
     297                 :            : {
     298                 :       2266 :   enum ch_type chtype = UNSET;
     299         [ +  + ]:       2266 :   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         [ +  + ]:       1642 :   else if (startswith (sname, ".zdebug"))
     323                 :            :     chtype = ZLIB_GNU;
     324                 :            :   else
     325                 :       1398 :     chtype = NONE;
     326                 :            : 
     327                 :       2266 :   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         [ +  + ]:       4821 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     484                 :            :     {
     485                 :       4591 :       size_t ndx = elf_ndxscn (scn);
     486         [ -  + ]:       4591 :       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                 :       4591 :       GElf_Shdr shdr_mem;
     494                 :       4591 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     495         [ -  + ]:       4591 :       if (shdr == NULL)
     496                 :            :         {
     497                 :          0 :           error (0, 0, "Couldn't get shdr for section %zd", ndx);
     498                 :          0 :           goto cleanup;
     499                 :            :         }
     500                 :            : 
     501                 :       4591 :       const char *sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
     502         [ -  + ]:       4591 :       if (sname == NULL)
     503                 :            :         {
     504                 :          0 :           error (0, 0, "Couldn't get name for section %zd", ndx);
     505                 :          0 :           goto cleanup;
     506                 :            :         }
     507                 :            : 
     508         [ +  + ]:       4591 :       if (section_name_matches (sname))
     509                 :            :         {
     510                 :       1198 :           enum ch_type schtype = get_section_chtype (scn, shdr, sname, ndx);
     511   [ +  +  +  + ]:       1198 :           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                 :            :             }
     531                 :            : 
     532   [ +  +  +  + ]:       1198 :           if (force || type != schtype)
     533                 :            :             {
     534         [ +  - ]:       1068 :               if (shdr->sh_type != SHT_NOBITS
     535         [ +  - ]:       1068 :                   && (shdr->sh_flags & SHF_ALLOC) == 0)
     536                 :            :                 {
     537                 :       1068 :                   set_section (sections, ndx);
     538                 :            :                   /* Check if we might want to change this section name.  */
     539         [ +  + ]:       1068 :                   if (! adjust_names
     540         [ +  + ]:        685 :                       && ((type != ZLIB_GNU
     541         [ +  + ]:        619 :                            && startswith (sname, ".zdebug"))
     542         [ +  + ]:        653 :                           || (type == ZLIB_GNU
     543         [ +  - ]:         66 :                               && startswith (sname, ".debug"))))
     544                 :            :                     adjust_names = true;
     545                 :            : 
     546                 :            :                   /* We need a buffer this large if we change the names.  */
     547                 :            :                   if (adjust_names)
     548                 :            :                     {
     549                 :        481 :                       size_t slen = strlen (sname);
     550                 :        481 :                       if (slen > maxnamelen)
     551                 :            :                         maxnamelen = slen;
     552                 :            :                     }
     553                 :            :                 }
     554                 :            :               else
     555         [ #  # ]:          0 :                 if (verbose >= 0)
     556         [ #  # ]:          0 :                   printf ("[%zd] %s ignoring %s section\n", ndx, sname,
     557                 :            :                           (shdr->sh_type == SHT_NOBITS ? "no bits" : "allocated"));
     558                 :            :             }
     559                 :            :         }
     560                 :            : 
     561         [ +  + ]:       4591 :       if (shdr->sh_type == SHT_SYMTAB)
     562                 :            :         {
     563                 :            :           /* Check if we might have to adjust the symbol name indexes.  */
     564         [ +  + ]:        230 :           if (shdr->sh_link == shdrstrndx)
     565                 :            :             {
     566         [ -  + ]:         96 :               if (symtabndx != 0)
     567                 :            :                 {
     568                 :          0 :                   error (0, 0,
     569                 :            :                          "Multiple symbol tables (%zd, %zd) using the same string table unsupported", symtabndx, ndx);
     570                 :          0 :                   goto cleanup;
     571                 :            :                 }
     572                 :            :               symtabndx = ndx;
     573                 :            :             }
     574                 :            :         }
     575                 :            : 
     576                 :            :       /* Keep track of last allocated data offset.  */
     577         [ +  + ]:       4591 :       if (layout)
     578         [ +  + ]:       4042 :         if ((shdr->sh_flags & SHF_ALLOC) != 0)
     579                 :            :           {
     580                 :       4448 :             GElf_Off off = shdr->sh_offset + (shdr->sh_type != SHT_NOBITS
     581         [ +  + ]:       2224 :                                               ? shdr->sh_size : 0);
     582                 :       2224 :             if (last_offset < off)
     583                 :       4591 :               last_offset = off;
     584                 :            :           }
     585                 :            :     }
     586                 :            : 
     587   [ +  +  -  + ]:        256 :   if (foutput == NULL && get_sections (sections, shnum) == 0)
     588                 :            :     {
     589         [ #  # ]:          0 :       if (verbose > 0)
     590                 :          0 :         printf ("Nothing to do.\n");
     591                 :          0 :       res = 0;
     592                 :          0 :       goto cleanup;
     593                 :            :     }
     594                 :            : 
     595         [ +  + ]:        230 :   if (adjust_names)
     596                 :            :     {
     597                 :         98 :       names = dwelf_strtab_init (true);
     598         [ -  + ]:         98 :       if (names == NULL)
     599                 :            :         {
     600                 :          0 :           error (0, 0, "Not enough memory for new strtab");
     601                 :          0 :           goto cleanup;
     602                 :            :         }
     603                 :         98 :       scnstrents = xmalloc (shnum
     604                 :            :                             * sizeof (Dwelf_Strent *));
     605                 :         98 :       scnnames = xcalloc (shnum, sizeof (char *));
     606                 :            :     }
     607                 :            : 
     608                 :            :   /* Create a new (temporary) ELF file for the result.  */
     609         [ +  + ]:        230 :   if (foutput == NULL)
     610                 :            :     {
     611                 :         26 :       size_t fname_len = strlen (fname);
     612                 :         26 :       fnew = xmalloc (fname_len + sizeof (".XXXXXX"));
     613                 :         26 :       strcpy (mempcpy (fnew, fname, fname_len), ".XXXXXX");
     614                 :         26 :       fdnew = mkstemp (fnew);
     615                 :            :     }
     616                 :            :   else
     617                 :            :     {
     618                 :        204 :       fnew = xstrdup (foutput);
     619                 :        204 :       fdnew = open (fnew, O_WRONLY | O_CREAT, st.st_mode & ALLPERMS);
     620                 :            :     }
     621                 :            : 
     622         [ -  + ]:        230 :   if (fdnew < 0)
     623                 :            :     {
     624                 :          0 :       error (0, errno, "Couldn't create output file %s", fnew);
     625                 :            :       /* Since we didn't create it we don't want to try to unlink it.  */
     626                 :          0 :       free (fnew);
     627                 :          0 :       fnew = NULL;
     628                 :          0 :       goto cleanup;
     629                 :            :     }
     630                 :            : 
     631                 :        230 :   elfnew = elf_begin (fdnew, ELF_C_WRITE, NULL);
     632         [ -  + ]:        230 :   if (elfnew == NULL)
     633                 :            :     {
     634                 :          0 :       error (0, 0, "Couldn't open new ELF %s for writing: %s",
     635                 :            :              fnew, elf_errmsg (-1));
     636                 :          0 :       goto cleanup;
     637                 :            :     }
     638                 :            : 
     639                 :            :   /* Create the new ELF header and copy over all the data.  */
     640         [ -  + ]:        230 :   if (gelf_newehdr (elfnew, gelf_getclass (elf)) == 0)
     641                 :            :     {
     642                 :          0 :       error (0, 0, "Couldn't create new ehdr: %s", elf_errmsg (-1));
     643                 :          0 :       goto cleanup;
     644                 :            :     }
     645                 :            : 
     646                 :        230 :   GElf_Ehdr newehdr;
     647         [ -  + ]:        230 :   if (gelf_getehdr (elfnew, &newehdr) == NULL)
     648                 :            :     {
     649                 :          0 :       error (0, 0, "Couldn't get new ehdr: %s", elf_errmsg (-1));
     650                 :          0 :       goto cleanup;
     651                 :            :     }
     652                 :            : 
     653                 :        230 :   newehdr.e_ident[EI_DATA] = ehdr.e_ident[EI_DATA];
     654                 :        230 :   newehdr.e_type = ehdr.e_type;
     655                 :        230 :   newehdr.e_machine = ehdr.e_machine;
     656                 :        230 :   newehdr.e_version = ehdr.e_version;
     657                 :        230 :   newehdr.e_entry = ehdr.e_entry;
     658                 :        230 :   newehdr.e_flags = ehdr.e_flags;
     659                 :            : 
     660         [ -  + ]:        230 :   if (gelf_update_ehdr (elfnew, &newehdr) == 0)
     661                 :            :     {
     662                 :          0 :       error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
     663                 :          0 :       goto cleanup;
     664                 :            :     }
     665                 :            : 
     666                 :            :   /* Copy over the phdrs as is.  */
     667         [ +  + ]:        230 :   if (phnum != 0)
     668                 :            :     {
     669         [ -  + ]:        213 :       if (gelf_newphdr (elfnew, phnum) == 0)
     670                 :            :         {
     671                 :          0 :           error (0, 0, "Couldn't create phdrs: %s", elf_errmsg (-1));
     672                 :          0 :           goto cleanup;
     673                 :            :         }
     674                 :            : 
     675         [ +  + ]:       1024 :       for (size_t cnt = 0; cnt < phnum; ++cnt)
     676                 :            :         {
     677                 :        811 :           GElf_Phdr phdr_mem;
     678                 :        811 :           GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
     679         [ -  + ]:        811 :           if (phdr == NULL)
     680                 :            :             {
     681                 :          0 :               error (0, 0, "Couldn't get phdr %zd: %s", cnt, elf_errmsg (-1));
     682                 :          0 :               goto cleanup;
     683                 :            :             }
     684         [ -  + ]:        811 :           if (gelf_update_phdr (elfnew, cnt, phdr) == 0)
     685                 :            :             {
     686                 :          0 :               error (0, 0, "Couldn't create phdr %zd: %s", cnt,
     687                 :            :                      elf_errmsg (-1));
     688                 :          0 :               goto cleanup;
     689                 :            :             }
     690                 :            :         }
     691                 :            :     }
     692                 :            : 
     693                 :            :   /* Possibly add a 'z' and zero terminator.  */
     694         [ +  + ]:        230 :   if (maxnamelen > 0)
     695                 :         98 :     snamebuf = xmalloc (maxnamelen + 2);
     696                 :            : 
     697                 :            :   /* We might want to read/adjust the section header strings and
     698                 :            :      symbol tables.  If so, and those sections are to be compressed
     699                 :            :      then we will have to decompress it during the collection pass and
     700                 :            :      compress it again in the fixup pass.  Don't compress unnecessary
     701                 :            :      and keep track of whether or not to compress them (later in the
     702                 :            :      fixup pass).  Also record the original size, so we can report the
     703                 :            :      difference later when we do compress.  */
     704                 :        230 :   enum ch_type shstrtab_compressed = UNSET;
     705                 :        230 :   size_t shstrtab_size = 0;
     706                 :        230 :   char *shstrtab_name = NULL;
     707                 :        230 :   char *shstrtab_newname = NULL;
     708                 :        230 :   enum ch_type symtab_compressed = UNSET;
     709                 :        230 :   size_t symtab_size = 0;
     710                 :        230 :   char *symtab_name = NULL;
     711                 :        230 :   char *symtab_newname = NULL;
     712                 :            : 
     713                 :            :   /* Collection pass.  Copy over the sections, (de)compresses matching
     714                 :            :      sections, collect names of sections and symbol table if
     715                 :            :      necessary.  */
     716                 :        230 :   scn = NULL;
     717         [ +  + ]:       4821 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     718                 :            :     {
     719                 :       4591 :       size_t ndx = elf_ndxscn (scn);
     720         [ -  + ]:       4591 :       assert (ndx < shnum);
     721                 :            : 
     722                 :            :       /* (de)compress if section matched.  */
     723                 :       4591 :       char *sname = NULL;
     724                 :       4591 :       char *newname = NULL;
     725         [ +  + ]:       4591 :       if (get_section (sections, ndx))
     726                 :            :         {
     727                 :       1068 :           GElf_Shdr shdr_mem;
     728                 :       1068 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     729         [ -  + ]:       1068 :           if (shdr == NULL)
     730                 :            :             {
     731                 :          0 :               error (0, 0, "Couldn't get shdr for section %zd", ndx);
     732                 :          0 :               goto cleanup;
     733                 :            :             }
     734                 :            : 
     735                 :       1068 :           uint64_t size = shdr->sh_size;
     736                 :       1068 :           sname = elf_strptr (elf, shdrstrndx, shdr->sh_name);
     737         [ -  + ]:       1068 :           if (sname == NULL)
     738                 :            :             {
     739                 :          0 :               error (0, 0, "Couldn't get name for section %zd", ndx);
     740                 :          0 :               goto cleanup;
     741                 :            :             }
     742                 :            : 
     743                 :            :           /* strdup sname, the shdrstrndx section itself might be
     744                 :            :              (de)compressed, invalidating the string pointers.  */
     745                 :       1068 :           sname = xstrdup (sname);
     746                 :            : 
     747                 :            : 
     748                 :            :           /* Detect source compression that is how is the section compressed
     749                 :            :              now.  */
     750                 :       1068 :           enum ch_type schtype = get_section_chtype (scn, shdr, sname, ndx);
     751         [ -  + ]:       1068 :           if (schtype == UNSET)
     752                 :          0 :             goto cleanup;
     753                 :            : 
     754                 :            :           /* We might want to decompress (and rename), but not
     755                 :            :              compress during this pass since we might need the section
     756                 :            :              data in later passes.  Skip those sections for now and
     757                 :            :              compress them in the fixup pass.  */
     758                 :       2136 :           bool skip_compress_section = (adjust_names
     759   [ +  +  +  - ]:       1068 :                                         && (ndx == shdrstrndx
     760         [ -  + ]:        481 :                                             || ndx == symtabndx));
     761                 :            : 
     762   [ -  +  +  + ]:       1068 :           switch (type)
     763                 :            :             {
     764                 :        244 :             case NONE:
     765         [ +  - ]:        244 :               if (schtype != NONE)
     766                 :            :                 {
     767         [ +  + ]:        244 :                   if (schtype == ZLIB_GNU)
     768                 :            :                     {
     769                 :        122 :                       snamebuf[0] = '.';
     770                 :        122 :                       strcpy (&snamebuf[1], &sname[2]);
     771                 :        122 :                       newname = snamebuf;
     772                 :            :                     }
     773         [ -  + ]:        244 :                   if (compress_section (scn, size, sname, NULL, ndx,
     774                 :            :                                         schtype, NONE, verbose > 0) < 0)
     775                 :          0 :                     goto cleanup;
     776                 :            :                 }
     777         [ #  # ]:          0 :               else if (verbose > 0)
     778                 :          0 :                 printf ("[%zd] %s already decompressed\n", ndx, sname);
     779                 :            :               break;
     780                 :            : 
     781                 :        359 :             case ZLIB_GNU:
     782         [ +  - ]:        359 :               if (startswith (sname, ".debug"))
     783                 :            :                 {
     784         [ +  + ]:        359 :                   if (schtype == ZLIB || schtype == ZSTD)
     785                 :            :                     {
     786                 :            :                       /* First decompress to recompress GNU style.
     787                 :            :                          Don't report even when verbose.  */
     788         [ -  + ]:         92 :                       if (compress_section (scn, size, sname, NULL, ndx,
     789                 :            :                                             schtype, NONE, false) < 0)
     790                 :          0 :                         goto cleanup;
     791                 :            :                     }
     792                 :            : 
     793                 :        359 :                   snamebuf[0] = '.';
     794                 :        359 :                   snamebuf[1] = 'z';
     795         [ -  + ]:        359 :                   strcpy (&snamebuf[2], &sname[1]);
     796                 :        359 :                   newname = snamebuf;
     797                 :            : 
     798         [ -  + ]:        359 :                   if (skip_compress_section)
     799                 :            :                     {
     800         [ #  # ]:          0 :                       if (ndx == shdrstrndx)
     801                 :            :                         {
     802                 :          0 :                           shstrtab_size = size;
     803                 :          0 :                           shstrtab_compressed = ZLIB_GNU;
     804                 :          0 :                           if (shstrtab_name != NULL
     805         [ #  # ]:          0 :                               || shstrtab_newname != NULL)
     806                 :            :                             {
     807                 :          0 :                               error (0, 0, "Internal error,"
     808                 :            :                                            " shstrtab_name already set,"
     809                 :            :                                            " while handling section [%zd] %s",
     810                 :            :                                      ndx, sname);
     811                 :          0 :                               goto cleanup;
     812                 :            :                             }
     813                 :          0 :                           shstrtab_name = xstrdup (sname);
     814                 :          0 :                           shstrtab_newname = xstrdup (newname);
     815                 :            :                         }
     816                 :            :                       else
     817                 :            :                         {
     818                 :          0 :                           symtab_size = size;
     819                 :          0 :                           symtab_compressed = ZLIB_GNU;
     820                 :          0 :                           symtab_name = xstrdup (sname);
     821                 :          0 :                           symtab_newname = xstrdup (newname);
     822                 :            :                         }
     823                 :            :                     }
     824                 :            :                   else
     825                 :            :                     {
     826                 :        359 :                       int result = compress_section (scn, size, sname, newname,
     827                 :            :                                                      ndx, NONE, type,
     828                 :            :                                                      verbose > 0);
     829         [ -  + ]:        359 :                       if (result < 0)
     830                 :          0 :                         goto cleanup;
     831                 :            : 
     832         [ +  + ]:        359 :                       if (result == 0)
     833                 :         48 :                         newname = NULL;
     834                 :            :                     }
     835                 :            :                 }
     836         [ #  # ]:          0 :               else if (verbose >= 0)
     837                 :            :                 {
     838         [ #  # ]:          0 :                   if (schtype == ZLIB_GNU)
     839                 :          0 :                     printf ("[%zd] %s unchanged, already GNU compressed\n",
     840                 :            :                             ndx, sname);
     841                 :            :                   else
     842                 :          0 :                     printf ("[%zd] %s cannot GNU compress section not starting with .debug\n",
     843                 :            :                             ndx, sname);
     844                 :            :                 }
     845                 :            :               break;
     846                 :            : 
     847                 :        465 :             case ZLIB:
     848                 :            :             case ZSTD:
     849         [ +  - ]:        465 :               if (schtype != type)
     850                 :            :                 {
     851         [ +  + ]:        465 :                   if (schtype != NONE)
     852                 :            :                     {
     853                 :            :                       /* Decompress first.  */
     854         [ -  + ]:         98 :                       if (compress_section (scn, size, sname, NULL, ndx,
     855                 :            :                                             schtype, NONE, false) < 0)
     856                 :          0 :                         goto cleanup;
     857                 :            : 
     858         [ +  - ]:         98 :                       if (schtype == ZLIB_GNU)
     859                 :            :                         {
     860                 :          0 :                           snamebuf[0] = '.';
     861                 :          0 :                           strcpy (&snamebuf[1], &sname[2]);
     862                 :          0 :                           newname = snamebuf;
     863                 :            :                         }
     864                 :            :                     }
     865                 :            : 
     866         [ -  + ]:        465 :                   if (skip_compress_section)
     867                 :            :                     {
     868         [ #  # ]:          0 :                       if (ndx == shdrstrndx)
     869                 :            :                         {
     870                 :          0 :                           shstrtab_size = size;
     871                 :          0 :                           shstrtab_compressed = type;
     872                 :          0 :                           if (shstrtab_name != NULL
     873         [ #  # ]:          0 :                               || shstrtab_newname != NULL)
     874                 :            :                             {
     875                 :          0 :                               error (0, 0, "Internal error,"
     876                 :            :                                            " shstrtab_name already set,"
     877                 :            :                                            " while handling section [%zd] %s",
     878                 :            :                                      ndx, sname);
     879                 :          0 :                               goto cleanup;
     880                 :            :                             }
     881                 :          0 :                           shstrtab_name = xstrdup (sname);
     882                 :          0 :                           shstrtab_newname = (newname == NULL
     883         [ #  # ]:          0 :                                               ? NULL : xstrdup (newname));
     884                 :            :                         }
     885                 :            :                       else
     886                 :            :                         {
     887                 :          0 :                           symtab_size = size;
     888                 :          0 :                           symtab_compressed = type;
     889                 :          0 :                           symtab_name = xstrdup (sname);
     890                 :          0 :                           symtab_newname = (newname == NULL
     891         [ #  # ]:          0 :                                             ? NULL : xstrdup (newname));
     892                 :            :                         }
     893                 :            :                     }
     894         [ -  + ]:        465 :                   else if (compress_section (scn, size, sname, newname, ndx,
     895                 :            :                                              NONE, type, verbose > 0) < 0)
     896                 :          0 :                     goto cleanup;
     897                 :            :                 }
     898         [ #  # ]:          0 :               else if (verbose > 0)
     899                 :          0 :                 printf ("[%zd] %s already compressed\n", ndx, sname);
     900                 :            :               break;
     901                 :            : 
     902                 :            :             case UNSET:
     903                 :            :               break;
     904                 :            :             }
     905                 :            : 
     906                 :       1068 :           free (sname);
     907                 :            :         }
     908                 :            : 
     909                 :       4591 :       Elf_Scn *newscn = elf_newscn (elfnew);
     910         [ -  + ]:       4591 :       if (newscn == NULL)
     911                 :            :         {
     912                 :          0 :           error (0, 0, "Couldn't create new section %zd", ndx);
     913                 :          0 :           goto cleanup;
     914                 :            :         }
     915                 :            : 
     916                 :       4591 :       GElf_Shdr shdr_mem;
     917                 :       4591 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     918         [ -  + ]:       4591 :       if (shdr == NULL)
     919                 :            :         {
     920                 :          0 :           error (0, 0, "Couldn't get shdr for section %zd", ndx);
     921                 :          0 :           goto cleanup;
     922                 :            :         }
     923                 :            : 
     924         [ -  + ]:       4591 :       if (gelf_update_shdr (newscn, shdr) == 0)
     925                 :            :         {
     926                 :          0 :           error (0, 0, "Couldn't update section header %zd", ndx);
     927                 :          0 :           goto cleanup;
     928                 :            :         }
     929                 :            : 
     930                 :            :       /* Except for the section header string table all data can be
     931                 :            :          copied as is.  The section header string table will be
     932                 :            :          created later and the symbol table might be fixed up if
     933                 :            :          necessary.  */
     934   [ +  +  +  + ]:       4591 :       if (! adjust_names || ndx != shdrstrndx)
     935                 :            :         {
     936                 :       4493 :           Elf_Data *data = elf_getdata (scn, NULL);
     937         [ -  + ]:       4493 :           if (data == NULL)
     938                 :            :             {
     939                 :          0 :               error (0, 0, "Couldn't get data from section %zd", ndx);
     940                 :          0 :               goto cleanup;
     941                 :            :             }
     942                 :            : 
     943                 :       4493 :           Elf_Data *newdata = elf_newdata (newscn);
     944         [ -  + ]:       4493 :           if (newdata == NULL)
     945                 :            :             {
     946                 :          0 :               error (0, 0, "Couldn't create new data for section %zd", ndx);
     947                 :          0 :               goto cleanup;
     948                 :            :             }
     949                 :            : 
     950                 :       4493 :           *newdata = *data;
     951                 :            :         }
     952                 :            : 
     953                 :            :       /* Keep track of the (new) section names.  */
     954         [ +  + ]:       4591 :       if (adjust_names)
     955                 :            :         {
     956                 :       1790 :           char *name;
     957         [ +  + ]:       1790 :           if (newname != NULL)
     958                 :            :             name = newname;
     959                 :            :           else
     960                 :            :             {
     961                 :       1357 :               name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
     962         [ -  + ]:       1357 :               if (name == NULL)
     963                 :            :                 {
     964                 :          0 :                   error (0, 0, "Couldn't get name for section [%zd]", ndx);
     965                 :          0 :                   goto cleanup;
     966                 :            :                 }
     967                 :            :             }
     968                 :            : 
     969                 :            :           /* We need to keep a copy of the name till the strtab is done.  */
     970                 :       1790 :           name = scnnames[ndx] = xstrdup (name);
     971         [ -  + ]:       1790 :           if ((scnstrents[ndx] = dwelf_strtab_add (names, name)) == NULL)
     972                 :            :             {
     973                 :          0 :               error (0, 0, "No memory to add section name string table");
     974                 :          0 :               goto cleanup;
     975                 :            :             }
     976                 :            : 
     977                 :            :           /* If the symtab shares strings then add those too.  */
     978         [ +  + ]:       1790 :           if (ndx == symtabndx)
     979                 :            :             {
     980                 :            :               /* If the section is (still) compressed we'll need to
     981                 :            :                  uncompress it first to adjust the data, then
     982                 :            :                  recompress it in the fixup pass.  */
     983         [ +  - ]:         40 :               if (symtab_compressed == UNSET)
     984                 :            :                 {
     985                 :         40 :                   size_t size = shdr->sh_size;
     986         [ -  + ]:         40 :                   if ((shdr->sh_flags == SHF_COMPRESSED) != 0)
     987                 :            :                     {
     988                 :            :                       /* Don't report the (internal) uncompression.  */
     989         [ #  # ]:          0 :                       if (compress_section (newscn, size, sname, NULL, ndx,
     990                 :            :                                             ZLIB, NONE, false) < 0)
     991                 :          0 :                         goto cleanup;
     992                 :            : 
     993                 :            :                       symtab_size = size;
     994                 :            :                       symtab_compressed = ZLIB;
     995                 :            :                     }
     996         [ -  + ]:         40 :                   else if (startswith (name, ".zdebug"))
     997                 :            :                     {
     998                 :            :                       /* Don't report the (internal) uncompression.  */
     999         [ #  # ]:          0 :                       if (compress_section (newscn, size, sname, NULL, ndx,
    1000                 :            :                                             ZLIB_GNU, NONE, false) < 0)
    1001                 :          0 :                         goto cleanup;
    1002                 :            : 
    1003                 :            :                       symtab_size = size;
    1004                 :            :                       symtab_compressed = ZLIB_GNU;
    1005                 :            :                     }
    1006                 :            :                 }
    1007                 :            : 
    1008                 :         40 :               Elf_Data *symd = elf_getdata (newscn, NULL);
    1009         [ -  + ]:         40 :               if (symd == NULL)
    1010                 :            :                 {
    1011                 :          0 :                   error (0, 0, "Couldn't get symtab data for section [%zd] %s",
    1012                 :            :                          ndx, name);
    1013                 :          0 :                   goto cleanup;
    1014                 :            :                 }
    1015                 :         40 :               size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
    1016                 :         40 :               size_t syms = symd->d_size / elsize;
    1017         [ -  + ]:         40 :               if (symstrents != NULL)
    1018                 :            :                 {
    1019                 :          0 :                   error (0, 0, "Internal error, symstrents already set,"
    1020                 :            :                          " while handling section [%zd] %s", ndx, name);
    1021                 :          0 :                   goto cleanup;
    1022                 :            :                 }
    1023                 :         40 :               symstrents = xmalloc (syms * sizeof (Dwelf_Strent *));
    1024         [ +  + ]:       2209 :               for (size_t i = 0; i < syms; i++)
    1025                 :            :                 {
    1026                 :       2169 :                   GElf_Sym sym_mem;
    1027                 :       2169 :                   GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
    1028         [ -  + ]:       2169 :                   if (sym == NULL)
    1029                 :            :                     {
    1030                 :          0 :                       error (0, 0, "Couldn't get symbol %zd", i);
    1031                 :          0 :                       goto cleanup;
    1032                 :            :                     }
    1033         [ +  + ]:       2169 :                   if (sym->st_name != 0)
    1034                 :            :                     {
    1035                 :            :                       /* Note we take the name from the original ELF,
    1036                 :            :                          since the new one will not have setup the
    1037                 :            :                          strtab yet.  */
    1038                 :       1561 :                       const char *symname = elf_strptr (elf, shdrstrndx,
    1039                 :            :                                                         sym->st_name);
    1040         [ -  + ]:       1561 :                       if (symname == NULL)
    1041                 :            :                         {
    1042                 :          0 :                           error (0, 0, "Couldn't get symbol %zd name", i);
    1043                 :          0 :                           goto cleanup;
    1044                 :            :                         }
    1045                 :       1561 :                       symstrents[i] = dwelf_strtab_add (names, symname);
    1046         [ -  + ]:       1561 :                       if (symstrents[i] == NULL)
    1047                 :            :                         {
    1048                 :          0 :                           error (0, 0, "No memory to add to symbol name");
    1049                 :          0 :                           goto cleanup;
    1050                 :            :                         }
    1051                 :            :                     }
    1052                 :            :                 }
    1053                 :            :             }
    1054                 :            :         }
    1055                 :            :     }
    1056                 :            : 
    1057         [ +  + ]:        230 :   if (adjust_names)
    1058                 :            :     {
    1059                 :            :       /* We got all needed strings, put the new data in the shstrtab.  */
    1060         [ +  + ]:         98 :       if (verbose > 0)
    1061                 :         80 :         printf ("[%zd] Updating section string table\n", shdrstrndx);
    1062                 :            : 
    1063                 :         98 :       scn = elf_getscn (elfnew, shdrstrndx);
    1064         [ -  + ]:         98 :       if (scn == NULL)
    1065                 :            :         {
    1066                 :          0 :           error (0, 0, "Couldn't get new section header string table [%zd]",
    1067                 :            :                  shdrstrndx);
    1068                 :          0 :           goto cleanup;
    1069                 :            :         }
    1070                 :            : 
    1071                 :         98 :       Elf_Data *data = elf_newdata (scn);
    1072         [ -  + ]:         98 :       if (data == NULL)
    1073                 :            :         {
    1074                 :          0 :           error (0, 0, "Couldn't create new section header string table data");
    1075                 :          0 :           goto cleanup;
    1076                 :            :         }
    1077         [ -  + ]:         98 :       if (dwelf_strtab_finalize (names, data) == NULL)
    1078                 :            :         {
    1079                 :          0 :           error (0, 0, "Not enough memory to create string table");
    1080                 :          0 :           goto cleanup;
    1081                 :            :         }
    1082                 :         98 :       namesbuf = data->d_buf;
    1083                 :            : 
    1084                 :         98 :       GElf_Shdr shdr_mem;
    1085                 :         98 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1086         [ -  + ]:         98 :       if (shdr == NULL)
    1087                 :            :         {
    1088                 :          0 :           error (0, 0, "Couldn't get shdr for new section strings %zd",
    1089                 :            :                  shdrstrndx);
    1090                 :          0 :           goto cleanup;
    1091                 :            :         }
    1092                 :            : 
    1093                 :            :       /* Note that we also might have to compress and possibly set
    1094                 :            :          sh_off below */
    1095                 :         98 :       shdr->sh_name = dwelf_strent_off (scnstrents[shdrstrndx]);
    1096                 :         98 :       shdr->sh_type = SHT_STRTAB;
    1097                 :         98 :       shdr->sh_flags = 0;
    1098                 :         98 :       shdr->sh_addr = 0;
    1099                 :         98 :       shdr->sh_offset = 0;
    1100                 :         98 :       shdr->sh_size = data->d_size;
    1101                 :         98 :       shdr->sh_link = SHN_UNDEF;
    1102                 :         98 :       shdr->sh_info = SHN_UNDEF;
    1103                 :         98 :       shdr->sh_addralign = 1;
    1104                 :         98 :       shdr->sh_entsize = 0;
    1105                 :            : 
    1106         [ -  + ]:         98 :       if (gelf_update_shdr (scn, shdr) == 0)
    1107                 :            :         {
    1108                 :          0 :           error (0, 0, "Couldn't update new section strings [%zd]",
    1109                 :            :                  shdrstrndx);
    1110                 :          0 :           goto cleanup;
    1111                 :            :         }
    1112                 :            : 
    1113                 :            :       /* We might have to compress the data if the user asked us to,
    1114                 :            :          or if the section was already compressed (and the user didn't
    1115                 :            :          ask for decompression).  Note somewhat identical code for
    1116                 :            :          symtab below.  */
    1117         [ +  - ]:         98 :       if (shstrtab_compressed == UNSET)
    1118                 :            :         {
    1119                 :            :           /* The user didn't ask for compression, but maybe it was
    1120                 :            :              compressed in the original ELF file.  */
    1121                 :         98 :           Elf_Scn *oldscn = elf_getscn (elf, shdrstrndx);
    1122         [ -  + ]:         98 :           if (oldscn == NULL)
    1123                 :            :             {
    1124                 :          0 :               error (0, 0, "Couldn't get section header string table [%zd]",
    1125                 :            :                      shdrstrndx);
    1126                 :          0 :               goto cleanup;
    1127                 :            :             }
    1128                 :            : 
    1129                 :         98 :           shdr = gelf_getshdr (oldscn, &shdr_mem);
    1130         [ -  + ]:         98 :           if (shdr == NULL)
    1131                 :            :             {
    1132                 :          0 :               error (0, 0, "Couldn't get shdr for old section strings [%zd]",
    1133                 :            :                      shdrstrndx);
    1134                 :          0 :               goto cleanup;
    1135                 :            :             }
    1136                 :            : 
    1137                 :         98 :           shstrtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
    1138         [ -  + ]:         98 :           if (shstrtab_name == NULL)
    1139                 :            :             {
    1140                 :          0 :               error (0, 0, "Couldn't get name for old section strings [%zd]",
    1141                 :            :                      shdrstrndx);
    1142                 :          0 :               goto cleanup;
    1143                 :            :             }
    1144                 :            : 
    1145                 :         98 :           shstrtab_size = shdr->sh_size;
    1146         [ +  - ]:         98 :           if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1147                 :            :             shstrtab_compressed = ZLIB;
    1148         [ -  + ]:         98 :           else if (startswith (shstrtab_name, ".zdebug"))
    1149                 :          0 :             shstrtab_compressed = ZLIB_GNU;
    1150                 :            :         }
    1151                 :            : 
    1152                 :            :       /* Should we (re)compress?  */
    1153         [ -  + ]:         98 :       if (shstrtab_compressed != UNSET)
    1154                 :            :         {
    1155         [ #  # ]:          0 :           if (compress_section (scn, shstrtab_size, shstrtab_name,
    1156                 :            :                                 shstrtab_newname, shdrstrndx,
    1157                 :            :                                 NONE, shstrtab_compressed,
    1158                 :            :                                 verbose > 0) < 0)
    1159                 :          0 :             goto cleanup;
    1160                 :            :         }
    1161                 :            :     }
    1162                 :            : 
    1163                 :            :   /* Make sure to re-get the new ehdr.  Adding phdrs and shdrs will
    1164                 :            :      have changed it.  */
    1165         [ -  + ]:        230 :   if (gelf_getehdr (elfnew, &newehdr) == NULL)
    1166                 :            :     {
    1167                 :          0 :       error (0, 0, "Couldn't re-get new ehdr: %s", elf_errmsg (-1));
    1168                 :          0 :       goto cleanup;
    1169                 :            :     }
    1170                 :            : 
    1171                 :            :   /* Set this after the sections have been created, otherwise section
    1172                 :            :      zero might not exist yet.  */
    1173         [ -  + ]:        230 :   if (setshdrstrndx (elfnew, &newehdr, shdrstrndx) != 0)
    1174                 :            :     {
    1175                 :          0 :       error (0, 0, "Couldn't set new shdrstrndx: %s", elf_errmsg (-1));
    1176                 :          0 :       goto cleanup;
    1177                 :            :     }
    1178                 :            : 
    1179                 :            :   /* Fixup pass.  Adjust string table references, symbol table and
    1180                 :            :      layout if necessary.  */
    1181         [ +  + ]:        230 :   if (layout || adjust_names)
    1182                 :            :     {
    1183                 :            :       scn = NULL;
    1184         [ +  + ]:       4535 :       while ((scn = elf_nextscn (elfnew, scn)) != NULL)
    1185                 :            :         {
    1186                 :       4311 :           size_t ndx = elf_ndxscn (scn);
    1187                 :            : 
    1188                 :       4311 :           GElf_Shdr shdr_mem;
    1189                 :       4311 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1190         [ -  + ]:       4311 :           if (shdr == NULL)
    1191                 :            :             {
    1192                 :          0 :               error (0, 0, "Couldn't get shdr for section %zd", ndx);
    1193                 :          0 :               goto cleanup;
    1194                 :            :             }
    1195                 :            : 
    1196                 :            :           /* Keep the offset of allocated sections so they are at the
    1197                 :            :              same place in the file. Add (possibly changed)
    1198                 :            :              unallocated ones after the allocated ones.  */
    1199         [ +  + ]:       4311 :           if ((shdr->sh_flags & SHF_ALLOC) == 0)
    1200                 :            :             {
    1201                 :            :               /* Zero means one.  No alignment constraints.  */
    1202                 :       2009 :               size_t addralign = shdr->sh_addralign ?: 1;
    1203                 :       2009 :               last_offset = (last_offset + addralign - 1) & ~(addralign - 1);
    1204                 :       2009 :               shdr->sh_offset = last_offset;
    1205         [ +  + ]:       2009 :               if (shdr->sh_type != SHT_NOBITS)
    1206                 :       2002 :                 last_offset += shdr->sh_size;
    1207                 :            :             }
    1208                 :            : 
    1209         [ +  + ]:       4311 :           if (adjust_names)
    1210                 :       1790 :             shdr->sh_name = dwelf_strent_off (scnstrents[ndx]);
    1211                 :            : 
    1212         [ -  + ]:       4311 :           if (gelf_update_shdr (scn, shdr) == 0)
    1213                 :            :             {
    1214                 :          0 :               error (0, 0, "Couldn't update section header %zd", ndx);
    1215                 :          0 :               goto cleanup;
    1216                 :            :             }
    1217                 :            : 
    1218         [ +  + ]:       4311 :           if (adjust_names && ndx == symtabndx)
    1219                 :            :             {
    1220         [ +  - ]:         40 :               if (verbose > 0)
    1221                 :         40 :                 printf ("[%zd] Updating symbol table\n", symtabndx);
    1222                 :            : 
    1223                 :         40 :               Elf_Data *symd = elf_getdata (scn, NULL);
    1224         [ -  + ]:         40 :               if (symd == NULL)
    1225                 :            :                 {
    1226                 :          0 :                   error (0, 0, "Couldn't get new symtab data section [%zd]",
    1227                 :            :                          ndx);
    1228                 :          0 :                   goto cleanup;
    1229                 :            :                 }
    1230                 :         40 :               size_t elsize = gelf_fsize (elfnew, ELF_T_SYM, 1, EV_CURRENT);
    1231                 :         40 :               size_t syms = symd->d_size / elsize;
    1232         [ +  + ]:       2209 :               for (size_t i = 0; i < syms; i++)
    1233                 :            :                 {
    1234                 :       2169 :                   GElf_Sym sym_mem;
    1235                 :       2169 :                   GElf_Sym *sym = gelf_getsym (symd, i, &sym_mem);
    1236         [ -  + ]:       2169 :                   if (sym == NULL)
    1237                 :            :                     {
    1238                 :          0 :                       error (0, 0, "2 Couldn't get symbol %zd", i);
    1239                 :          0 :                       goto cleanup;
    1240                 :            :                     }
    1241                 :            : 
    1242         [ +  + ]:       2169 :                   if (sym->st_name != 0)
    1243                 :            :                     {
    1244                 :       1561 :                       sym->st_name = dwelf_strent_off (symstrents[i]);
    1245                 :            : 
    1246         [ -  + ]:       1561 :                       if (gelf_update_sym (symd, i, sym) == 0)
    1247                 :            :                         {
    1248                 :          0 :                           error (0, 0, "Couldn't update symbol %zd", i);
    1249                 :          0 :                           goto cleanup;
    1250                 :            :                         }
    1251                 :            :                     }
    1252                 :            :                 }
    1253                 :            : 
    1254                 :            :               /* We might have to compress the data if the user asked
    1255                 :            :                  us to, or if the section was already compressed (and
    1256                 :            :                  the user didn't ask for decompression).  Note
    1257                 :            :                  somewhat identical code for shstrtab above.  */
    1258         [ +  - ]:         40 :               if (symtab_compressed == UNSET)
    1259                 :            :                 {
    1260                 :            :                   /* The user didn't ask for compression, but maybe it was
    1261                 :            :                      compressed in the original ELF file.  */
    1262                 :         40 :                   Elf_Scn *oldscn = elf_getscn (elf, symtabndx);
    1263         [ -  + ]:         40 :                   if (oldscn == NULL)
    1264                 :            :                     {
    1265                 :          0 :                       error (0, 0, "Couldn't get symbol table [%zd]",
    1266                 :            :                              symtabndx);
    1267                 :          0 :                       goto cleanup;
    1268                 :            :                     }
    1269                 :            : 
    1270                 :         40 :                   shdr = gelf_getshdr (oldscn, &shdr_mem);
    1271         [ -  + ]:         40 :                   if (shdr == NULL)
    1272                 :            :                     {
    1273                 :          0 :                       error (0, 0, "Couldn't get old symbol table shdr [%zd]",
    1274                 :            :                              symtabndx);
    1275                 :          0 :                       goto cleanup;
    1276                 :            :                     }
    1277                 :            : 
    1278                 :         40 :                   symtab_name = elf_strptr (elf, shdrstrndx, shdr->sh_name);
    1279         [ -  + ]:         40 :                   if (symtab_name == NULL)
    1280                 :            :                     {
    1281                 :          0 :                       error (0, 0, "Couldn't get old symbol table name [%zd]",
    1282                 :            :                              symtabndx);
    1283                 :          0 :                       goto cleanup;
    1284                 :            :                     }
    1285                 :            : 
    1286                 :         40 :                   symtab_size = shdr->sh_size;
    1287         [ +  - ]:         40 :                   if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
    1288                 :            :                     symtab_compressed = ZLIB;
    1289         [ -  + ]:         40 :                   else if (startswith (symtab_name, ".zdebug"))
    1290                 :          0 :                     symtab_compressed = ZLIB_GNU;
    1291                 :            :                 }
    1292                 :            : 
    1293                 :            :               /* Should we (re)compress?  */
    1294         [ -  + ]:         40 :               if (symtab_compressed != UNSET)
    1295                 :            :                 {
    1296         [ #  # ]:          0 :                   if (compress_section (scn, symtab_size, symtab_name,
    1297                 :            :                                         symtab_newname, symtabndx,
    1298                 :            :                                         NONE, symtab_compressed,
    1299                 :            :                                         verbose > 0) < 0)
    1300                 :          0 :                     goto cleanup;
    1301                 :            :                 }
    1302                 :            :             }
    1303                 :            :         }
    1304                 :            :     }
    1305                 :            : 
    1306                 :            :   /* If we have phdrs we want elf_update to layout the SHF_ALLOC
    1307                 :            :      sections precisely as in the original file.  In that case we are
    1308                 :            :      also responsible for setting phoff and shoff */
    1309         [ +  + ]:        230 :   if (layout)
    1310                 :            :     {
    1311         [ -  + ]:        213 :       if (gelf_getehdr (elfnew, &newehdr) == NULL)
    1312                 :            :         {
    1313                 :          0 :           error (0, 0, "Couldn't get ehdr: %s", elf_errmsg (-1));
    1314                 :          0 :           goto cleanup;
    1315                 :            :         }
    1316                 :            : 
    1317                 :            :       /* Position the shdrs after the last (unallocated) section.  */
    1318                 :        213 :       const size_t offsize = gelf_fsize (elfnew, ELF_T_OFF, 1, EV_CURRENT);
    1319                 :        213 :       newehdr.e_shoff = ((last_offset + offsize - 1)
    1320                 :        213 :                          & ~((GElf_Off) (offsize - 1)));
    1321                 :            : 
    1322                 :            :       /* The phdrs go in the same place as in the original file.
    1323                 :            :          Normally right after the ELF header.  */
    1324                 :        213 :       newehdr.e_phoff = ehdr.e_phoff;
    1325                 :            : 
    1326         [ -  + ]:        213 :       if (gelf_update_ehdr (elfnew, &newehdr) == 0)
    1327                 :            :         {
    1328                 :          0 :           error (0, 0, "Couldn't update ehdr: %s", elf_errmsg (-1));
    1329                 :          0 :           goto cleanup;
    1330                 :            :         }
    1331                 :            :     }
    1332                 :            : 
    1333                 :        230 :   elf_flagelf (elfnew, ELF_C_SET, ((layout ? ELF_F_LAYOUT : 0)
    1334         [ +  - ]:        460 :                                    | (permissive ? ELF_F_PERMISSIVE : 0)));
    1335                 :            : 
    1336         [ -  + ]:        230 :   if (elf_update (elfnew, ELF_C_WRITE) < 0)
    1337                 :            :     {
    1338                 :          0 :       error (0, 0, "Couldn't write %s: %s", fnew, elf_errmsg (-1));
    1339                 :          0 :       goto cleanup;
    1340                 :            :     }
    1341                 :            : 
    1342                 :        230 :   elf_end (elfnew);
    1343                 :        230 :   elfnew = NULL;
    1344                 :            : 
    1345                 :            :   /* Try to match mode and owner.group of the original file.
    1346                 :            :      Note to set suid bits we have to make sure the owner is setup
    1347                 :            :      correctly first. Otherwise fchmod will drop them silently
    1348                 :            :      or fchown may clear them.  */
    1349         [ -  + ]:        230 :   if (fchown (fdnew, st.st_uid, st.st_gid) != 0)
    1350         [ #  # ]:          0 :     if (verbose >= 0)
    1351                 :          0 :       error (0, errno, "Couldn't fchown %s", fnew);
    1352         [ -  + ]:        230 :   if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0)
    1353         [ #  # ]:          0 :     if (verbose >= 0)
    1354                 :          0 :       error (0, errno, "Couldn't fchmod %s", fnew);
    1355                 :            : 
    1356                 :            :   /* Finally replace the old file with the new file.  */
    1357         [ +  + ]:        230 :   if (foutput == NULL)
    1358         [ -  + ]:         26 :     if (rename (fnew, fname) != 0)
    1359                 :            :       {
    1360                 :          0 :         error (0, errno, "Couldn't rename %s to %s", fnew, fname);
    1361                 :          0 :         goto cleanup;
    1362                 :            :       }
    1363                 :            : 
    1364                 :            :   /* We are finally done with the new file, don't unlink it now.  */
    1365                 :        230 :   free (fnew);
    1366                 :        230 :   fnew = NULL;
    1367                 :        230 :   res = 0;
    1368                 :            : 
    1369                 :        230 : cleanup:
    1370                 :        230 :   elf_end (elf);
    1371                 :        230 :   close (fd);
    1372                 :            : 
    1373                 :        230 :   elf_end (elfnew);
    1374                 :        230 :   close (fdnew);
    1375                 :            : 
    1376         [ -  + ]:        230 :   if (fnew != NULL)
    1377                 :            :     {
    1378                 :          0 :       unlink (fnew);
    1379                 :          0 :       free (fnew);
    1380                 :          0 :       fnew = NULL;
    1381                 :            :     }
    1382                 :            : 
    1383                 :        230 :   free (snamebuf);
    1384         [ +  + ]:        230 :   if (names != NULL)
    1385                 :            :     {
    1386                 :         98 :       dwelf_strtab_free (names);
    1387                 :         98 :       free (scnstrents);
    1388                 :         98 :       free (symstrents);
    1389                 :         98 :       free (namesbuf);
    1390         [ +  - ]:         98 :       if (scnnames != NULL)
    1391                 :            :         {
    1392         [ +  + ]:       1986 :           for (size_t n = 0; n < shnum; n++)
    1393                 :       1888 :             free (scnnames[n]);
    1394                 :         98 :           free (scnnames);
    1395                 :            :         }
    1396                 :            :     }
    1397                 :            : 
    1398                 :        230 :   free (sections);
    1399                 :        230 :   return res;
    1400                 :            : }
    1401                 :            : 
    1402                 :            : int
    1403                 :        214 : main (int argc, char **argv)
    1404                 :            : {
    1405                 :        214 :   const struct argp_option options[] =
    1406                 :            :     {
    1407                 :            :       { "output", 'o', "FILE", 0,
    1408                 :            :         N_("Place (de)compressed output into FILE"),
    1409                 :            :         0 },
    1410                 :            :       { "type", 't', "TYPE", 0,
    1411                 :            :         N_("What type of compression to apply. TYPE can be 'none' (decompress), 'zlib' (ELF ZLIB compression, the default, 'zlib-gabi' is an alias), "
    1412                 :            :            "'zlib-gnu' (.zdebug GNU style compression, 'gnu' is an alias) or 'zstd' (ELF ZSTD compression)"),
    1413                 :            :         0 },
    1414                 :            :       { "name", 'n', "SECTION", 0,
    1415                 :            :         N_("SECTION name to (de)compress, SECTION is an extended wildcard pattern (defaults to '.?(z)debug*')"),
    1416                 :            :         0 },
    1417                 :            :       { "verbose", 'v', NULL, 0,
    1418                 :            :         N_("Print a message for each section being (de)compressed"),
    1419                 :            :         0 },
    1420                 :            :       { "force", 'f', NULL, 0,
    1421                 :            :         N_("Force compression of section even if it would become larger or update/rewrite the file even if no section would be (de)compressed"),
    1422                 :            :         0 },
    1423                 :            :       { "permissive", 'p', NULL, 0,
    1424                 :            :         N_("Relax a few rules to handle slightly broken ELF files"),
    1425                 :            :         0 },
    1426                 :            :       { "quiet", 'q', NULL, 0,
    1427                 :            :         N_("Be silent when a section cannot be compressed"),
    1428                 :            :         0 },
    1429                 :            :       { NULL, 0, NULL, 0, NULL, 0 }
    1430                 :            :     };
    1431                 :            : 
    1432                 :        214 :   const struct argp argp =
    1433                 :            :     {
    1434                 :            :       .options = options,
    1435                 :            :       .parser = parse_opt,
    1436                 :            :       .args_doc = N_("FILE..."),
    1437                 :            :       .doc = N_("Compress or decompress sections in an ELF file.")
    1438                 :            :     };
    1439                 :            : 
    1440                 :        214 :   int remaining;
    1441         [ +  - ]:        214 :   if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
    1442                 :            :     return EXIT_FAILURE;
    1443                 :            : 
    1444                 :            :   /* Should already be handled by ARGP_KEY_NO_ARGS case above,
    1445                 :            :      just sanity check.  */
    1446         [ -  + ]:        214 :   if (remaining >= argc)
    1447                 :          0 :     error_exit (0, N_("No input file given"));
    1448                 :            : 
    1449                 :            :   /* Likewise for the ARGP_KEY_ARGS case above, an extra sanity check.  */
    1450   [ +  +  -  + ]:        214 :   if (foutput != NULL && remaining + 1 < argc)
    1451                 :          0 :     error_exit (0, N_("Only one input file allowed together with '-o'"));
    1452                 :            : 
    1453                 :        214 :   elf_version (EV_CURRENT);
    1454                 :            : 
    1455                 :            :   /* Process all the remaining files.  */
    1456                 :        214 :   int result = 0;
    1457                 :        230 :   do
    1458                 :        230 :     result |= process_file (argv[remaining]);
    1459         [ +  + ]:        230 :   while (++remaining < argc);
    1460                 :            : 
    1461                 :        214 :   free_patterns ();
    1462                 :        214 :   return result;
    1463                 :            : }

Generated by: LCOV version 1.16