LCOV - code coverage report
Current view: top level - src - elfcompress.c (source / functions) Hit Total Coverage
Test: elfutils-0.177 Lines: 406 613 66.2 %
Date: 2019-08-14 14:28:26 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13