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

Generated by: LCOV version 1.13