LCOV - code coverage report
Current view: top level - src - elfcompress.c (source / functions) Coverage Total Hit
Test: elfutils-0.195 Lines: 66.5 % 656 436
Test Date: 2026-05-28 14:32:52 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 62.5 % 435 272

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

Generated by: LCOV version 2.0-1