LCOV - code coverage report
Current view: top level - src - strip.c (source / functions) Hit Total Coverage
Test: elfutils-0.174 Lines: 760 1024 74.2 %
Date: 2018-09-14 13:30:33 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Discard section not used at runtime from object files.
       2             :    Copyright (C) 2000-2012, 2014, 2015, 2016, 2017 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             :    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
       5             : 
       6             :    This file is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    elfutils is distributed in the hope that it will be useful, but
      12             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18             : 
      19             : #ifdef HAVE_CONFIG_H
      20             : # include <config.h>
      21             : #endif
      22             : 
      23             : #include <argp.h>
      24             : #include <assert.h>
      25             : #include <byteswap.h>
      26             : #include <endian.h>
      27             : #include <fcntl.h>
      28             : #include <fnmatch.h>
      29             : #include <gelf.h>
      30             : #include <libelf.h>
      31             : #include <libintl.h>
      32             : #include <locale.h>
      33             : #include <stdbool.h>
      34             : #include <stdio.h>
      35             : #include <stdio_ext.h>
      36             : #include <stdlib.h>
      37             : #include <string.h>
      38             : #include <unistd.h>
      39             : #include <sys/stat.h>
      40             : #include <sys/time.h>
      41             : 
      42             : #include <elf-knowledge.h>
      43             : #include <libebl.h>
      44             : #include "libdwelf.h"
      45             : #include <libeu.h>
      46             : #include <system.h>
      47             : #include <printversion.h>
      48             : 
      49             : typedef uint8_t GElf_Byte;
      50             : 
      51             : /* Name and version of program.  */
      52             : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
      53             : 
      54             : /* Bug report address.  */
      55             : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
      56             : 
      57             : 
      58             : /* Values for the parameters which have no short form.  */
      59             : #define OPT_REMOVE_COMMENT      0x100
      60             : #define OPT_PERMISSIVE          0x101
      61             : #define OPT_STRIP_SECTIONS      0x102
      62             : #define OPT_RELOC_DEBUG         0x103
      63             : #define OPT_KEEP_SECTION        0x104
      64             : 
      65             : 
      66             : /* Definitions of arguments for argp functions.  */
      67             : static const struct argp_option options[] =
      68             : {
      69             :   { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
      70             :   { "output", 'o', "FILE", 0, N_("Place stripped output into FILE"), 0 },
      71             :   { NULL, 'f', "FILE", 0, N_("Extract the removed sections into FILE"), 0 },
      72             :   { NULL, 'F', "FILE", 0, N_("Embed name FILE instead of -f argument"), 0 },
      73             : 
      74             :   { NULL, 0, NULL, 0, N_("Output options:"), 0 },
      75             :   { "strip-all", 's', NULL, OPTION_HIDDEN, NULL, 0 },
      76             :   { "strip-debug", 'g', NULL, 0, N_("Remove all debugging symbols"), 0 },
      77             :   { NULL, 'd', NULL, OPTION_ALIAS, NULL, 0 },
      78             :   { NULL, 'S', NULL, OPTION_ALIAS, NULL, 0 },
      79             :   { "strip-sections", OPT_STRIP_SECTIONS, NULL, 0,
      80             :     N_("Remove section headers (not recommended)"), 0 },
      81             :   { "preserve-dates", 'p', NULL, 0,
      82             :     N_("Copy modified/access timestamps to the output"), 0 },
      83             :   { "reloc-debug-sections", OPT_RELOC_DEBUG, NULL, 0,
      84             :     N_("Resolve all trivial relocations between debug sections if the removed sections are placed in a debug file (only relevant for ET_REL files, operation is not reversable, needs -f)"), 0 },
      85             :   { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0,
      86             :     N_("Remove .comment section"), 0 },
      87             :   { "remove-section", 'R', "SECTION", 0, N_("Remove the named section.  SECTION is an extended wildcard pattern.  May be given more than once.  Only non-allocated sections can be removed."), 0 },
      88             :   { "keep-section", OPT_KEEP_SECTION, "SECTION", 0, N_("Keep the named section.  SECTION is an extended wildcard pattern.  May be given more than once."), 0 },
      89             :   { "permissive", OPT_PERMISSIVE, NULL, 0,
      90             :     N_("Relax a few rules to handle slightly broken ELF files"), 0 },
      91             :   { NULL, 0, NULL, 0, NULL, 0 }
      92             : };
      93             : 
      94             : /* Short description of program.  */
      95             : static const char doc[] = N_("Discard symbols from object files.");
      96             : 
      97             : /* Strings for arguments in help texts.  */
      98             : static const char args_doc[] = N_("[FILE...]");
      99             : 
     100             : /* Prototype for option handler.  */
     101             : static error_t parse_opt (int key, char *arg, struct argp_state *state);
     102             : 
     103             : /* Data structure to communicate with argp functions.  */
     104             : static struct argp argp =
     105             : {
     106             :   options, parse_opt, args_doc, doc, NULL, NULL, NULL
     107             : };
     108             : 
     109             : 
     110             : /* Print symbols in file named FNAME.  */
     111             : static int process_file (const char *fname);
     112             : 
     113             : /* Handle one ELF file.  */
     114             : static int handle_elf (int fd, Elf *elf, const char *prefix,
     115             :                        const char *fname, mode_t mode, struct timespec tvp[2]);
     116             : 
     117             : /* Handle all files contained in the archive.  */
     118             : static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
     119             :                       struct timespec tvp[2]) __attribute__ ((unused));
     120             : 
     121             : static int debug_fd = -1;
     122             : static char *tmp_debug_fname = NULL;
     123             : 
     124             : /* Close debug file descriptor, if opened. And remove temporary debug file.  */
     125             : static void cleanup_debug (void);
     126             : 
     127             : #define INTERNAL_ERROR(fname) \
     128             :   do { \
     129             :     cleanup_debug (); \
     130             :     error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"),      \
     131             :            fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1)); \
     132             :   } while (0)
     133             : 
     134             : 
     135             : /* Name of the output file.  */
     136             : static const char *output_fname;
     137             : 
     138             : /* Name of the debug output file.  */
     139             : static const char *debug_fname;
     140             : 
     141             : /* Name to pretend the debug output file has.  */
     142             : static const char *debug_fname_embed;
     143             : 
     144             : /* If true output files shall have same date as the input file.  */
     145             : static bool preserve_dates;
     146             : 
     147             : /* If true .comment sections will be removed.  */
     148             : static bool remove_comment;
     149             : 
     150             : /* If true remove all debug sections.  */
     151             : static bool remove_debug;
     152             : 
     153             : /* If true remove all section headers.  */
     154             : static bool remove_shdrs;
     155             : 
     156             : /* If true relax some ELF rules for input files.  */
     157             : static bool permissive;
     158             : 
     159             : /* If true perform relocations between debug sections.  */
     160             : static bool reloc_debug;
     161             : 
     162             : /* Sections the user explicitly wants to keep or remove.  */
     163             : struct section_pattern
     164             : {
     165             :   char *pattern;
     166             :   struct section_pattern *next;
     167             : };
     168             : 
     169             : static struct section_pattern *keep_secs = NULL;
     170             : static struct section_pattern *remove_secs = NULL;
     171             : 
     172             : static void
     173          10 : add_pattern (struct section_pattern **patterns, const char *pattern)
     174             : {
     175          10 :   struct section_pattern *p = xmalloc (sizeof *p);
     176          10 :   p->pattern = xstrdup (pattern);
     177          10 :   p->next = *patterns;
     178          10 :   *patterns = p;
     179          10 : }
     180             : 
     181             : static void
     182         170 : free_sec_patterns (struct section_pattern *patterns)
     183             : {
     184         170 :   struct section_pattern *pattern = patterns;
     185         350 :   while (pattern != NULL)
     186             :     {
     187          10 :       struct section_pattern *p = pattern;
     188          10 :       pattern = p->next;
     189          10 :       free (p->pattern);
     190          10 :       free (p);
     191             :     }
     192         170 : }
     193             : 
     194             : static void
     195          85 : free_patterns (void)
     196             : {
     197          85 :   free_sec_patterns (keep_secs);
     198          85 :   free_sec_patterns (remove_secs);
     199          85 : }
     200             : 
     201             : static bool
     202             : section_name_matches (struct section_pattern *patterns, const char *name)
     203             : {
     204      398731 :   struct section_pattern *pattern = patterns;
     205      398982 :   while (pattern != NULL)
     206             :     {
     207         269 :       if (fnmatch (pattern->pattern, name, FNM_EXTMATCH) == 0)
     208             :         return true;
     209         251 :       pattern = pattern->next;
     210             :     }
     211             :   return false;
     212             : }
     213             : 
     214             : 
     215             : int
     216          85 : main (int argc, char *argv[])
     217             : {
     218             :   int remaining;
     219          85 :   int result = 0;
     220             : 
     221             :   /* We use no threads here which can interfere with handling a stream.  */
     222          85 :   __fsetlocking (stdin, FSETLOCKING_BYCALLER);
     223          85 :   __fsetlocking (stdout, FSETLOCKING_BYCALLER);
     224          85 :   __fsetlocking (stderr, FSETLOCKING_BYCALLER);
     225             : 
     226             :   /* Set locale.  */
     227          85 :   setlocale (LC_ALL, "");
     228             : 
     229             :   /* Make sure the message catalog can be found.  */
     230          85 :   bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
     231             : 
     232             :   /* Initialize the message catalog.  */
     233          85 :   textdomain (PACKAGE_TARNAME);
     234             : 
     235             :   /* Parse and process arguments.  */
     236          85 :   if (argp_parse (&argp, argc, argv, 0, &remaining, NULL) != 0)
     237             :     return EXIT_FAILURE;
     238             : 
     239          85 :   if (reloc_debug && debug_fname == NULL)
     240             :     error (EXIT_FAILURE, 0,
     241           0 :            gettext ("--reloc-debug-sections used without -f"));
     242             : 
     243             :   /* Tell the library which version we are expecting.  */
     244          85 :   elf_version (EV_CURRENT);
     245             : 
     246          85 :   if (remaining == argc)
     247             :     /* The user didn't specify a name so we use a.out.  */
     248           5 :     result = process_file ("a.out");
     249             :   else
     250             :     {
     251             :       /* If we have seen the '-o' or '-f' option there must be exactly one
     252             :          input file.  */
     253          80 :       if ((output_fname != NULL || debug_fname != NULL)
     254          66 :           && remaining + 1 < argc)
     255           0 :         error (EXIT_FAILURE, 0, gettext ("\
     256             : Only one input file allowed together with '-o' and '-f'"));
     257             : 
     258             :       /* Process all the remaining files.  */
     259             :       do
     260          80 :         result |= process_file (argv[remaining]);
     261          80 :       while (++remaining < argc);
     262             :     }
     263             : 
     264          85 :   free_patterns ();
     265          85 :   return result;
     266             : }
     267             : 
     268             : 
     269             : /* Handle program arguments.  */
     270             : static error_t
     271         596 : parse_opt (int key, char *arg, struct argp_state *state)
     272             : {
     273         596 :   switch (key)
     274             :     {
     275          49 :     case 'f':
     276          49 :       if (debug_fname != NULL)
     277             :         {
     278           0 :           error (0, 0, gettext ("-f option specified twice"));
     279           0 :           return EINVAL;
     280             :         }
     281          49 :       debug_fname = arg;
     282          49 :       break;
     283             : 
     284           6 :     case 'F':
     285           6 :       if (debug_fname_embed != NULL)
     286             :         {
     287           0 :           error (0, 0, gettext ("-F option specified twice"));
     288           0 :           return EINVAL;
     289             :         }
     290           6 :       debug_fname_embed = arg;
     291           6 :       break;
     292             : 
     293          69 :     case 'o':
     294          69 :       if (output_fname != NULL)
     295             :         {
     296           0 :           error (0, 0, gettext ("-o option specified twice"));
     297           0 :           return EINVAL;
     298             :         }
     299          69 :       output_fname = arg;
     300          69 :       break;
     301             : 
     302           0 :     case 'p':
     303           0 :       preserve_dates = true;
     304           0 :       break;
     305             : 
     306          11 :     case OPT_RELOC_DEBUG:
     307          11 :       reloc_debug = true;
     308          11 :       break;
     309             : 
     310           1 :     case OPT_REMOVE_COMMENT:
     311           1 :       remove_comment = true;
     312           1 :       break;
     313             : 
     314           4 :     case 'R':
     315           4 :       if (fnmatch (arg, ".comment", FNM_EXTMATCH) == 0)
     316           0 :         remove_comment = true;
     317           4 :       add_pattern (&remove_secs, arg);
     318           4 :       break;
     319             : 
     320           6 :     case OPT_KEEP_SECTION:
     321           6 :       add_pattern (&keep_secs, arg);
     322           6 :       break;
     323             : 
     324          25 :     case 'g':
     325             :     case 'd':
     326             :     case 'S':
     327          25 :       remove_debug = true;
     328          25 :       break;
     329             : 
     330           0 :     case OPT_STRIP_SECTIONS:
     331           0 :       remove_shdrs = true;
     332           0 :       break;
     333             : 
     334           0 :     case OPT_PERMISSIVE:
     335           0 :       permissive = true;
     336           0 :       break;
     337             : 
     338             :     case 's':                   /* Ignored for compatibility.  */
     339             :       break;
     340             : 
     341          85 :     case ARGP_KEY_SUCCESS:
     342          85 :       if (remove_comment == true
     343           2 :           && section_name_matches (keep_secs, ".comment"))
     344             :         {
     345           0 :           argp_error (state,
     346           0 :                       gettext ("cannot both keep and remove .comment section"));
     347           0 :           return EINVAL;
     348             :         }
     349             :       break;
     350             : 
     351             :     default:
     352             :       return ARGP_ERR_UNKNOWN;
     353             :     }
     354             :   return 0;
     355             : }
     356             : 
     357             : 
     358             : static int
     359          85 : process_file (const char *fname)
     360             : {
     361             :   /* If we have to preserve the modify and access timestamps get them
     362             :      now.  We cannot use fstat() after opening the file since the open
     363             :      would change the access time.  */
     364             :   struct stat pre_st;
     365             :   struct timespec tv[2];
     366          85 :  again:
     367          85 :   if (preserve_dates)
     368             :     {
     369           0 :       if (stat (fname, &pre_st) != 0)
     370             :         {
     371           0 :           error (0, errno, gettext ("cannot stat input file '%s'"), fname);
     372           0 :           return 1;
     373             :         }
     374             : 
     375             :       /* If we have to preserve the timestamp, we need it in the
     376             :          format utimes() understands.  */
     377           0 :       tv[0] = pre_st.st_atim;
     378           0 :       tv[1] = pre_st.st_mtim;
     379             :     }
     380             : 
     381             :   /* Open the file.  */
     382         170 :   int fd = open (fname, output_fname == NULL ? O_RDWR : O_RDONLY);
     383          85 :   if (fd == -1)
     384             :     {
     385           0 :       error (0, errno, gettext ("while opening '%s'"), fname);
     386           0 :       return 1;
     387             :     }
     388             : 
     389             :   /* We always use fstat() even if we called stat() before.  This is
     390             :      done to make sure the information returned by stat() is for the
     391             :      same file.  */
     392             :   struct stat st;
     393          85 :   if (fstat (fd, &st) != 0)
     394             :     {
     395           0 :       error (0, errno, gettext ("cannot stat input file '%s'"), fname);
     396           0 :       return 1;
     397             :     }
     398             :   /* Paranoid mode on.  */
     399          85 :   if (preserve_dates
     400           0 :       && (st.st_ino != pre_st.st_ino || st.st_dev != pre_st.st_dev))
     401             :     {
     402             :       /* We detected a race.  Try again.  */
     403           0 :       close (fd);
     404           0 :       goto again;
     405             :     }
     406             : 
     407             :   /* Now get the ELF descriptor.  */
     408          85 :   Elf *elf = elf_begin (fd, output_fname == NULL ? ELF_C_RDWR : ELF_C_READ,
     409             :                         NULL);
     410             :   int result;
     411          85 :   switch (elf_kind (elf))
     412             :     {
     413          85 :     case ELF_K_ELF:
     414          85 :       result = handle_elf (fd, elf, NULL, fname, st.st_mode & ACCESSPERMS,
     415          85 :                            preserve_dates ? tv : NULL);
     416          85 :       break;
     417             : 
     418           0 :     case ELF_K_AR:
     419             :       /* It is not possible to strip the content of an archive direct
     420             :          the output to a specific file.  */
     421           0 :       if (unlikely (output_fname != NULL || debug_fname != NULL))
     422             :         {
     423           0 :           error (0, 0, gettext ("%s: cannot use -o or -f when stripping archive"),
     424             :                  fname);
     425           0 :           result = 1;
     426             :         }
     427             :       else
     428             :         {
     429             :           /* We would like to support ar archives, but currently it just
     430             :              doesn't work at all since we call elf_clone on the members
     431             :              which doesn't really support ar members.
     432             :              result = handle_ar (fd, elf, NULL, fname,
     433             :                                  preserve_dates ? tv : NULL);
     434             :            */
     435           0 :           error (0, 0, gettext ("%s: no support for stripping archive"),
     436             :                  fname);
     437           0 :           result = 1;
     438             :         }
     439             :       break;
     440             : 
     441           0 :     default:
     442           0 :       error (0, 0, gettext ("%s: File format not recognized"), fname);
     443           0 :       result = 1;
     444           0 :       break;
     445             :     }
     446             : 
     447          85 :   if (unlikely (elf_end (elf) != 0))
     448           0 :     INTERNAL_ERROR (fname);
     449             : 
     450          85 :   close (fd);
     451             : 
     452          85 :   return result;
     453             : }
     454             : 
     455             : 
     456             : /* Maximum size of array allocated on stack.  */
     457             : #define MAX_STACK_ALLOC (400 * 1024)
     458             : 
     459             : static int
     460          85 : handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
     461             :             mode_t mode, struct timespec tvp[2])
     462             : {
     463          85 :   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
     464          85 :   size_t fname_len = strlen (fname) + 1;
     465          85 :   char *fullname = alloca (prefix_len + 1 + fname_len);
     466          85 :   char *cp = fullname;
     467          85 :   Elf *debugelf = NULL;
     468          85 :   tmp_debug_fname = NULL;
     469          85 :   int result = 0;
     470          85 :   size_t shdridx = 0;
     471             :   size_t shstrndx;
     472             :   struct shdr_info
     473             :   {
     474             :     Elf_Scn *scn;
     475             :     GElf_Shdr shdr;
     476             :     Elf_Data *data;
     477             :     Elf_Data *debug_data;
     478             :     const char *name;
     479             :     Elf32_Word idx;             /* Index in new file.  */
     480             :     Elf32_Word old_sh_link;     /* Original value of shdr.sh_link.  */
     481             :     Elf32_Word symtab_idx;
     482             :     Elf32_Word version_idx;
     483             :     Elf32_Word group_idx;
     484             :     Elf32_Word group_cnt;
     485             :     Elf_Scn *newscn;
     486             :     Dwelf_Strent *se;
     487             :     Elf32_Word *newsymidx;
     488          85 :   } *shdr_info = NULL;
     489             :   Elf_Scn *scn;
     490             :   size_t cnt;
     491             :   size_t idx;
     492             :   bool changes;
     493             :   GElf_Ehdr newehdr_mem;
     494             :   GElf_Ehdr *newehdr;
     495             :   GElf_Ehdr debugehdr_mem;
     496             :   GElf_Ehdr *debugehdr;
     497          85 :   Dwelf_Strtab *shst = NULL;
     498             :   Elf_Data debuglink_crc_data;
     499          85 :   bool any_symtab_changes = false;
     500          85 :   Elf_Data *shstrtab_data = NULL;
     501          85 :   void *debuglink_buf = NULL;
     502             : 
     503             :   /* Create the full name of the file.  */
     504          85 :   if (prefix != NULL)
     505             :     {
     506           0 :       cp = mempcpy (cp, prefix, prefix_len);
     507           0 :       *cp++ = ':';
     508             :     }
     509         170 :   memcpy (cp, fname, fname_len);
     510             : 
     511             :   /* If we are not replacing the input file open a new file here.  */
     512          85 :   if (output_fname != NULL)
     513             :     {
     514         138 :       fd = open (output_fname, O_RDWR | O_CREAT, mode);
     515          69 :       if (unlikely (fd == -1))
     516             :         {
     517           0 :           error (0, errno, gettext ("cannot open '%s'"), output_fname);
     518           0 :           return 1;
     519             :         }
     520             :     }
     521             : 
     522          85 :   debug_fd = -1;
     523             : 
     524             :   /* Get the EBL handling.  Removing all debugging symbols with the -g
     525             :      option or resolving all relocations between debug sections with
     526             :      the --reloc-debug-sections option are currently the only reasons
     527             :      we need EBL so don't open the backend unless necessary.  */
     528          85 :   Ebl *ebl = NULL;
     529          85 :   if (remove_debug || reloc_debug)
     530             :     {
     531          36 :       ebl = ebl_openbackend (elf);
     532          36 :       if (ebl == NULL)
     533             :         {
     534           0 :           error (0, errno, gettext ("cannot open EBL backend"));
     535           0 :           result = 1;
     536           0 :           goto fail;
     537             :         }
     538             :     }
     539             : 
     540             :   /* Open the additional file the debug information will be stored in.  */
     541          85 :   if (debug_fname != NULL)
     542             :     {
     543             :       /* Create a temporary file name.  We do not want to overwrite
     544             :          the debug file if the file would not contain any
     545             :          information.  */
     546          49 :       size_t debug_fname_len = strlen (debug_fname);
     547          49 :       tmp_debug_fname = (char *) xmalloc (debug_fname_len + sizeof (".XXXXXX"));
     548         147 :       strcpy (mempcpy (tmp_debug_fname, debug_fname, debug_fname_len),
     549             :               ".XXXXXX");
     550             : 
     551          49 :       debug_fd = mkstemp (tmp_debug_fname);
     552          49 :       if (unlikely (debug_fd == -1))
     553             :         {
     554           0 :           error (0, errno, gettext ("cannot open '%s'"), debug_fname);
     555           0 :           result = 1;
     556           0 :           goto fail;
     557             :         }
     558             :     }
     559             : 
     560             :   /* Get the information from the old file.  */
     561             :   GElf_Ehdr ehdr_mem;
     562          85 :   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
     563          85 :   if (ehdr == NULL)
     564           0 :     INTERNAL_ERROR (fname);
     565             : 
     566             :   /* Get the section header string table index.  */
     567          85 :   if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
     568             :     {
     569           0 :       cleanup_debug ();
     570             :       error (EXIT_FAILURE, 0,
     571           0 :              gettext ("cannot get section header string table index"));
     572             :     }
     573             : 
     574             :   /* Get the number of phdrs in the old file.  */
     575             :   size_t phnum;
     576          85 :   if (elf_getphdrnum (elf, &phnum) != 0)
     577             :     {
     578           0 :       cleanup_debug ();
     579           0 :       error (EXIT_FAILURE, 0, gettext ("cannot get number of phdrs"));
     580             :     }
     581             : 
     582             :   /* We now create a new ELF descriptor for the same file.  We
     583             :      construct it almost exactly in the same way with some information
     584             :      dropped.  */
     585             :   Elf *newelf;
     586          85 :   if (output_fname != NULL)
     587          69 :     newelf = elf_begin (fd, ELF_C_WRITE_MMAP, NULL);
     588             :   else
     589          16 :     newelf = elf_clone (elf, ELF_C_EMPTY);
     590             : 
     591          85 :   if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0)
     592          85 :       || (ehdr->e_type != ET_REL
     593          52 :           && unlikely (gelf_newphdr (newelf, phnum) == 0)))
     594             :     {
     595           0 :       error (0, 0, gettext ("cannot create new file '%s': %s"),
     596           0 :              output_fname ?: fname, elf_errmsg (-1));
     597             :       goto fail;
     598             :     }
     599             : 
     600             :   /* Copy over the old program header if needed.  */
     601          85 :   if (ehdr->e_type != ET_REL)
     602         440 :     for (cnt = 0; cnt < phnum; ++cnt)
     603             :       {
     604             :         GElf_Phdr phdr_mem;
     605         388 :         GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
     606         388 :         if (phdr == NULL
     607         388 :             || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0))
     608           0 :           INTERNAL_ERROR (fname);
     609             :       }
     610             : 
     611          85 :   if (debug_fname != NULL)
     612             :     {
     613             :       /* Also create an ELF descriptor for the debug file */
     614          49 :       debugelf = elf_begin (debug_fd, ELF_C_WRITE_MMAP, NULL);
     615          49 :       if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0)
     616          49 :           || (ehdr->e_type != ET_REL
     617          23 :               && unlikely (gelf_newphdr (debugelf, phnum) == 0)))
     618             :         {
     619           0 :           error (0, 0, gettext ("cannot create new file '%s': %s"),
     620             :                  debug_fname, elf_errmsg (-1));
     621             :           goto fail_close;
     622             :         }
     623             : 
     624             :       /* Copy over the old program header if needed.  */
     625          49 :       if (ehdr->e_type != ET_REL)
     626         197 :         for (cnt = 0; cnt < phnum; ++cnt)
     627             :           {
     628             :             GElf_Phdr phdr_mem;
     629         174 :             GElf_Phdr *phdr = gelf_getphdr (elf, cnt, &phdr_mem);
     630         174 :             if (phdr == NULL
     631         174 :                 || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0))
     632           0 :               INTERNAL_ERROR (fname);
     633             :           }
     634             :     }
     635             : 
     636             :   /* Number of sections.  */
     637             :   size_t shnum;
     638          85 :   if (unlikely (elf_getshdrnum (elf, &shnum) < 0))
     639             :     {
     640           0 :       error (0, 0, gettext ("cannot determine number of sections: %s"),
     641             :              elf_errmsg (-1));
     642             :       goto fail_close;
     643             :     }
     644             : 
     645          85 :   if (shstrndx >= shnum)
     646             :     goto illformed;
     647             : 
     648             : #define elf_assert(test) do { if (!(test)) goto illformed; } while (0)
     649             : 
     650             :   /* Storage for section information.  We leave room for two more
     651             :      entries since we unconditionally create a section header string
     652             :      table.  Maybe some weird tool created an ELF file without one.
     653             :      The other one is used for the debug link section.  */
     654          85 :   if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
     655           3 :     shdr_info = (struct shdr_info *) xcalloc (shnum + 2,
     656             :                                               sizeof (struct shdr_info));
     657             :   else
     658             :     {
     659          82 :       shdr_info = (struct shdr_info *) alloca ((shnum + 2)
     660             :                                                * sizeof (struct shdr_info));
     661          82 :       memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info));
     662             :     }
     663             : 
     664             :   /* Track whether allocated sections all come before non-allocated ones.  */
     665          85 :   bool seen_allocated = false;
     666          85 :   bool seen_unallocated = false;
     667          85 :   bool mixed_allocated_unallocated = false;
     668             : 
     669             :   /* Prepare section information data structure.  */
     670          85 :   scn = NULL;
     671          85 :   cnt = 1;
     672      199529 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     673             :     {
     674             :       /* This should always be true (i.e., there should not be any
     675             :          holes in the numbering).  */
     676      199359 :       elf_assert (elf_ndxscn (scn) == cnt);
     677             : 
     678      199359 :       shdr_info[cnt].scn = scn;
     679             : 
     680             :       /* Get the header.  */
     681      199359 :       if (gelf_getshdr (scn, &shdr_info[cnt].shdr) == NULL)
     682           0 :         INTERNAL_ERROR (fname);
     683             : 
     684             :       /* Normally (in non-ET_REL files) we see all allocated sections first,
     685             :          then all non-allocated.  */
     686      199359 :       if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
     687             :         seen_unallocated = true;
     688             :       else
     689             :         {
     690        1503 :           if (seen_unallocated && seen_allocated)
     691         272 :             mixed_allocated_unallocated = true;
     692             :           seen_allocated = true;
     693             :         }
     694             : 
     695             :       /* Get the name of the section.  */
     696      199359 :       shdr_info[cnt].name = elf_strptr (elf, shstrndx,
     697      199359 :                                         shdr_info[cnt].shdr.sh_name);
     698      199359 :       if (shdr_info[cnt].name == NULL)
     699             :         {
     700           0 :         illformed:
     701           1 :           error (0, 0, gettext ("illformed file '%s'"), fname);
     702             :           goto fail_close;
     703             :         }
     704             : 
     705             :       /* Sanity check the user.  */
     706      398718 :       if (section_name_matches (remove_secs, shdr_info[cnt].name))
     707             :         {
     708           6 :           if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0)
     709             :             {
     710           0 :               error (0, 0,
     711           0 :                      gettext ("Cannot remove allocated section '%s'"),
     712             :                      shdr_info[cnt].name);
     713           0 :               result = 1;
     714           0 :               goto fail_close;
     715             :             }
     716             : 
     717          12 :           if (section_name_matches (keep_secs, shdr_info[cnt].name))
     718             :             {
     719           0 :               error (0, 0,
     720           0 :                      gettext ("Cannot both keep and remove section '%s'"),
     721           0 :                      shdr_info[cnt].name);
     722           0 :               result = 1;
     723           0 :               goto fail_close;
     724             :             }
     725             :         }
     726             : 
     727             :       /* Mark them as present but not yet investigated.  */
     728      199359 :       shdr_info[cnt].idx = 1;
     729             : 
     730             :       /* Remember the shdr.sh_link value.  */
     731      199359 :       shdr_info[cnt].old_sh_link = shdr_info[cnt].shdr.sh_link;
     732      199359 :       if (shdr_info[cnt].old_sh_link >= shnum)
     733             :         goto illformed;
     734             : 
     735             :       /* Sections in files other than relocatable object files which
     736             :          not loaded can be freely moved by us.  In theory we can also
     737             :          freely move around allocated nobits sections.  But we don't
     738             :          to keep the layout of all allocated sections as similar as
     739             :          possible to the original file.  In relocatable object files
     740             :          everything can be moved.  */
     741      199359 :       if (ehdr->e_type == ET_REL
     742      198328 :           || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
     743      198166 :         shdr_info[cnt].shdr.sh_offset = 0;
     744             : 
     745             :       /* If this is an extended section index table store an
     746             :          appropriate reference.  */
     747      199359 :       if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX))
     748             :         {
     749           0 :           elf_assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0);
     750           0 :           shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx = cnt;
     751             :         }
     752      199359 :       else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP))
     753             :         {
     754             :           /* Cross-reference the sections contained in the section
     755             :              group.  */
     756           6 :           shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
     757           6 :           if (shdr_info[cnt].data == NULL
     758           6 :               || shdr_info[cnt].data->d_size < sizeof (Elf32_Word))
     759           0 :             INTERNAL_ERROR (fname);
     760             : 
     761             :           /* XXX Fix for unaligned access.  */
     762           6 :           Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
     763             :           size_t inner;
     764          22 :           for (inner = 1;
     765          16 :                inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
     766          10 :                ++inner)
     767             :             {
     768          10 :               if (grpref[inner] < shnum)
     769          10 :                 shdr_info[grpref[inner]].group_idx = cnt;
     770             :               else
     771             :                 goto illformed;
     772             :             }
     773             : 
     774           6 :           if (inner == 1 || (inner == 2 && (grpref[0] & GRP_COMDAT) == 0))
     775             :             /* If the section group contains only one element and this
     776             :                is n COMDAT section we can drop it right away.  */
     777           0 :             shdr_info[cnt].idx = 0;
     778             :           else
     779           6 :             shdr_info[cnt].group_cnt = inner - 1;
     780             :         }
     781      199353 :       else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym))
     782             :         {
     783          52 :           elf_assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0);
     784          52 :           shdr_info[shdr_info[cnt].shdr.sh_link].version_idx = cnt;
     785             :         }
     786             : 
     787             :       /* If this section is part of a group make sure it is not
     788             :          discarded right away.  */
     789      199359 :       if ((shdr_info[cnt].shdr.sh_flags & SHF_GROUP) != 0)
     790             :         {
     791          10 :           elf_assert (shdr_info[cnt].group_idx != 0);
     792             : 
     793          10 :           if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
     794             :             {
     795             :               /* The section group section will be removed.  */
     796           0 :               shdr_info[cnt].group_idx = 0;
     797           0 :               shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP;
     798             :             }
     799             :         }
     800             : 
     801             :       /* Increment the counter.  */
     802      199359 :       ++cnt;
     803             :     }
     804             : 
     805             :   /* Now determine which sections can go away.  The general rule is that
     806             :      all sections which are not used at runtime are stripped out.  But
     807             :      there are a few exceptions:
     808             : 
     809             :      - special sections named ".comment" and ".note" are kept
     810             :      - OS or architecture specific sections are kept since we might not
     811             :        know how to handle them
     812             :      - if a section is referred to from a section which is not removed
     813             :        in the sh_link or sh_info element it cannot be removed either
     814             :      - the user might have explicitly said to remove or keep a section
     815             :   */
     816      199444 :   for (cnt = 1; cnt < shnum; ++cnt)
     817             :     /* Check whether the section can be removed.  Since we will create
     818             :        a new .shstrtab assume it will be removed too.  */
     819      398718 :     if (remove_shdrs ? !(shdr_info[cnt].shdr.sh_flags & SHF_ALLOC)
     820      398718 :         : (ebl_section_strip_p (ebl, &shdr_info[cnt].shdr,
     821      199359 :                                 shdr_info[cnt].name, remove_comment,
     822             :                                 remove_debug)
     823       67216 :            || cnt == shstrndx
     824      333741 :            || section_name_matches (remove_secs, shdr_info[cnt].name)))
     825             :       {
     826             :         /* The user might want to explicitly keep this one.  */
     827      264348 :         if (section_name_matches (keep_secs, shdr_info[cnt].name))
     828           6 :           continue;
     829             : 
     830             :         /* For now assume this section will be removed.  */
     831      132168 :         shdr_info[cnt].idx = 0;
     832             : 
     833      132168 :         idx = shdr_info[cnt].group_idx;
     834      264337 :         while (idx != 0)
     835             :           {
     836             :             /* The section group data is already loaded.  */
     837           9 :             elf_assert (shdr_info[idx].data != NULL
     838             :                         && shdr_info[idx].data->d_buf != NULL
     839             :                         && shdr_info[idx].data->d_size >= sizeof (Elf32_Word));
     840             : 
     841             :             /* If the references section group is a normal section
     842             :                group and has one element remaining, or if it is an
     843             :                empty COMDAT section group it is removed.  */
     844           6 :             bool is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0]
     845           3 :                               & GRP_COMDAT) != 0;
     846             : 
     847           3 :             --shdr_info[idx].group_cnt;
     848           3 :             if ((!is_comdat && shdr_info[idx].group_cnt == 1)
     849           3 :                 || (is_comdat && shdr_info[idx].group_cnt == 0))
     850             :               {
     851           1 :                 shdr_info[idx].idx = 0;
     852             :                 /* Continue recursively.  */
     853           1 :                 idx = shdr_info[idx].group_idx;
     854             :               }
     855             :             else
     856             :               break;
     857             :           }
     858             :       }
     859             : 
     860             :   /* Mark the SHT_NULL section as handled.  */
     861          85 :   shdr_info[0].idx = 2;
     862             : 
     863             : 
     864             :   /* Handle exceptions: section groups and cross-references.  We might
     865             :      have to repeat this a few times since the resetting of the flag
     866             :      might propagate.  */
     867             :   do
     868             :     {
     869          85 :       changes = false;
     870             : 
     871      199444 :       for (cnt = 1; cnt < shnum; ++cnt)
     872             :         {
     873      199359 :           if (shdr_info[cnt].idx == 0)
     874             :             {
     875             :               /* If a relocation section is marked as being removed make
     876             :                  sure the section it is relocating is removed, too.  */
     877      264212 :               if (shdr_info[cnt].shdr.sh_type == SHT_REL
     878      132106 :                    || shdr_info[cnt].shdr.sh_type == SHT_RELA)
     879             :                 {
     880         311 :                   if (shdr_info[cnt].shdr.sh_info >= shnum)
     881             :                     goto illformed;
     882         311 :                   else if (shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0)
     883         148 :                     shdr_info[cnt].idx = 1;
     884             :                 }
     885             : 
     886             :               /* If a group section is marked as being removed make
     887             :                  sure all the sections it contains are being removed, too.  */
     888      132106 :               if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
     889             :                 {
     890             :                   Elf32_Word *grpref;
     891           6 :                   grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
     892          13 :                   for (size_t in = 1;
     893           7 :                        in < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
     894           1 :                        ++in)
     895           6 :                     if (grpref[in] < shnum)
     896             :                       {
     897           6 :                         if (shdr_info[grpref[in]].idx != 0)
     898             :                           {
     899           5 :                             shdr_info[cnt].idx = 1;
     900           5 :                             break;
     901             :                           }
     902             :                       }
     903             :                     else
     904             :                       goto illformed;
     905             :                 }
     906             :             }
     907             : 
     908      199359 :           if (shdr_info[cnt].idx == 1)
     909             :             {
     910             :               /* The content of symbol tables we don't remove must not
     911             :                  reference any section which we do remove.  Otherwise
     912             :                  we cannot remove the section.  */
     913       67406 :               if (debug_fname != NULL
     914       66607 :                   && shdr_info[cnt].debug_data == NULL
     915      133102 :                   && (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
     916       66551 :                       || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB))
     917             :                 {
     918             :                   /* Make sure the data is loaded.  */
     919          29 :                   if (shdr_info[cnt].data == NULL)
     920             :                     {
     921             :                       shdr_info[cnt].data
     922          29 :                         = elf_getdata (shdr_info[cnt].scn, NULL);
     923          29 :                       if (shdr_info[cnt].data == NULL)
     924           0 :                         INTERNAL_ERROR (fname);
     925             :                     }
     926          29 :                   Elf_Data *symdata = shdr_info[cnt].data;
     927             : 
     928             :                   /* If there is an extended section index table load it
     929             :                      as well.  */
     930          29 :                   if (shdr_info[cnt].symtab_idx != 0
     931           0 :                       && shdr_info[shdr_info[cnt].symtab_idx].data == NULL)
     932             :                     {
     933           0 :                       elf_assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB);
     934             : 
     935             :                       shdr_info[shdr_info[cnt].symtab_idx].data
     936           0 :                         = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
     937             :                                        NULL);
     938           0 :                       if (shdr_info[shdr_info[cnt].symtab_idx].data == NULL)
     939           0 :                         INTERNAL_ERROR (fname);
     940             :                     }
     941          29 :                   Elf_Data *xndxdata
     942          29 :                     = shdr_info[shdr_info[cnt].symtab_idx].data;
     943             : 
     944             :                   /* Go through all symbols and make sure the section they
     945             :                      reference is not removed.  */
     946          29 :                   size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
     947             : 
     948        1075 :                   for (size_t inner = 0;
     949        1046 :                        inner < shdr_info[cnt].data->d_size / elsize;
     950        1017 :                        ++inner)
     951             :                     {
     952             :                       GElf_Sym sym_mem;
     953             :                       Elf32_Word xndx;
     954        1017 :                       GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
     955             :                                                         inner, &sym_mem,
     956             :                                                         &xndx);
     957        1017 :                       if (sym == NULL)
     958           0 :                         INTERNAL_ERROR (fname);
     959             : 
     960        1017 :                       size_t scnidx = sym->st_shndx;
     961        1017 :                       if (scnidx == SHN_UNDEF || scnidx >= shnum
     962         555 :                           || (scnidx >= SHN_LORESERVE
     963             :                               && scnidx <= SHN_HIRESERVE
     964         555 :                               && scnidx != SHN_XINDEX)
     965             :                           /* Don't count in the section symbols.  */
     966         544 :                           || GELF_ST_TYPE (sym->st_info) == STT_SECTION)
     967             :                         /* This is no section index, leave it alone.  */
     968         699 :                         continue;
     969         318 :                       else if (scnidx == SHN_XINDEX)
     970           0 :                         scnidx = xndx;
     971             : 
     972         318 :                       if (scnidx >= shnum)
     973             :                         goto illformed;
     974             : 
     975         318 :                       if (shdr_info[scnidx].idx == 0)
     976             :                         /* This symbol table has a real symbol in
     977             :                            a discarded section.  So preserve the
     978             :                            original table in the debug file.  Unless
     979             :                            it is a redundant data marker to a debug
     980             :                            (data only) section.  */
     981          12 :                         if (! (ebl_section_strip_p (ebl,
     982           4 :                                                     &shdr_info[scnidx].shdr,
     983             :                                                     shdr_info[scnidx].name,
     984             :                                                     remove_comment,
     985             :                                                     remove_debug)
     986           4 :                                && ebl_data_marker_symbol (ebl, sym,
     987           8 :                                         elf_strptr (elf,
     988           4 :                                                     shdr_info[cnt].shdr.sh_link,
     989           4 :                                                     sym->st_name))))
     990           0 :                           shdr_info[cnt].debug_data = symdata;
     991             :                     }
     992             :                 }
     993             : 
     994             :               /* Cross referencing happens:
     995             :                  - for the cases the ELF specification says.  That are
     996             :                    + SHT_DYNAMIC in sh_link to string table
     997             :                    + SHT_HASH in sh_link to symbol table
     998             :                    + SHT_REL and SHT_RELA in sh_link to symbol table
     999             :                    + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table
    1000             :                    + SHT_GROUP in sh_link to symbol table
    1001             :                    + SHT_SYMTAB_SHNDX in sh_link to symbol table
    1002             :                    Other (OS or architecture-specific) sections might as
    1003             :                    well use this field so we process it unconditionally.
    1004             :                  - references inside section groups
    1005             :                  - specially marked references in sh_info if the SHF_INFO_LINK
    1006             :                  flag is set
    1007             :               */
    1008             : 
    1009       67406 :               if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0)
    1010             :                 {
    1011          62 :                   shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1;
    1012          62 :                   changes |= shdr_info[cnt].shdr.sh_link < cnt;
    1013             :                 }
    1014             : 
    1015             :               /* Handle references through sh_info.  */
    1016       67406 :               if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
    1017             :                 {
    1018         251 :                   if (shdr_info[cnt].shdr.sh_info >= shnum)
    1019             :                     goto illformed;
    1020         251 :                   else if ( shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0)
    1021             :                     {
    1022           0 :                       shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
    1023           0 :                       changes |= shdr_info[cnt].shdr.sh_info < cnt;
    1024             :                     }
    1025             :                 }
    1026             : 
    1027             :               /* Mark the section as investigated.  */
    1028       67406 :               shdr_info[cnt].idx = 2;
    1029             :             }
    1030             : 
    1031      199359 :           if (debug_fname != NULL
    1032      132671 :               && (shdr_info[cnt].idx == 0 || shdr_info[cnt].debug_data != NULL))
    1033             :             {
    1034             :               /* This section is being preserved in the debug file.
    1035             :                  Sections it refers to must be preserved there too.
    1036             : 
    1037             :                  In this pass we mark sections to be preserved in both
    1038             :                  files by setting the .debug_data pointer to the original
    1039             :                  file's .data pointer.  Below, we'll copy the section
    1040             :                  contents.  */
    1041             : 
    1042       66248 :               inline void check_preserved (size_t i)
    1043             :               {
    1044       66248 :                 if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0
    1045         159 :                     && shdr_info[i].debug_data == NULL)
    1046             :                   {
    1047          56 :                     if (shdr_info[i].data == NULL)
    1048          56 :                       shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL);
    1049          56 :                     if (shdr_info[i].data == NULL)
    1050           0 :                       INTERNAL_ERROR (fname);
    1051             : 
    1052          56 :                     shdr_info[i].debug_data = shdr_info[i].data;
    1053          56 :                     changes |= i < cnt;
    1054             :                   }
    1055       66248 :               }
    1056             : 
    1057       66120 :               check_preserved (shdr_info[cnt].shdr.sh_link);
    1058       66120 :               if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
    1059         128 :                 check_preserved (shdr_info[cnt].shdr.sh_info);
    1060             :             }
    1061             :         }
    1062             :     }
    1063          85 :   while (changes);
    1064             : 
    1065             :   /* Copy the removed sections to the debug output file.
    1066             :      The ones that are not removed in the stripped file are SHT_NOBITS.  */
    1067          85 :   if (debug_fname != NULL)
    1068             :     {
    1069      132720 :       for (cnt = 1; cnt < shnum; ++cnt)
    1070             :         {
    1071      132671 :           scn = elf_newscn (debugelf);
    1072      132671 :           if (scn == NULL)
    1073             :             {
    1074           0 :               cleanup_debug ();
    1075           0 :               error (EXIT_FAILURE, 0,
    1076           0 :                      gettext ("while generating output file: %s"),
    1077             :                      elf_errmsg (-1));
    1078             :             }
    1079             : 
    1080      265342 :           bool discard_section = (shdr_info[cnt].idx > 0
    1081       66607 :                                   && shdr_info[cnt].debug_data == NULL
    1082       66551 :                                   && shdr_info[cnt].shdr.sh_type != SHT_NOTE
    1083       66493 :                                   && shdr_info[cnt].shdr.sh_type != SHT_GROUP
    1084      199159 :                                   && cnt != shstrndx);
    1085             : 
    1086             :           /* Set the section header in the new file.  */
    1087      132671 :           GElf_Shdr debugshdr = shdr_info[cnt].shdr;
    1088      132671 :           if (discard_section)
    1089       66488 :             debugshdr.sh_type = SHT_NOBITS;
    1090             : 
    1091      132671 :           if (unlikely (gelf_update_shdr (scn, &debugshdr) == 0))
    1092             :             /* There cannot be any overflows.  */
    1093           0 :             INTERNAL_ERROR (fname);
    1094             : 
    1095             :           /* Get the data from the old file if necessary. */
    1096      132671 :           if (shdr_info[cnt].data == NULL)
    1097             :             {
    1098      132580 :               shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
    1099      132580 :               if (shdr_info[cnt].data == NULL)
    1100           0 :                 INTERNAL_ERROR (fname);
    1101             :             }
    1102             : 
    1103             :           /* Set the data.  This is done by copying from the old file.  */
    1104      132671 :           Elf_Data *debugdata = elf_newdata (scn);
    1105      132671 :           if (debugdata == NULL)
    1106           0 :             INTERNAL_ERROR (fname);
    1107             : 
    1108             :           /* Copy the structure.  This data may be modified in place
    1109             :              before we write out the file.  */
    1110      132671 :           *debugdata = *shdr_info[cnt].data;
    1111      132671 :           if (discard_section)
    1112       66488 :             debugdata->d_buf = NULL;
    1113       66183 :           else if (shdr_info[cnt].debug_data != NULL
    1114       66127 :                    || shdr_info[cnt].shdr.sh_type == SHT_GROUP)
    1115             :             {
    1116             :               /* Copy the original data before it gets modified.  */
    1117          62 :               shdr_info[cnt].debug_data = debugdata;
    1118          62 :               if (debugdata->d_buf == NULL)
    1119           0 :                 INTERNAL_ERROR (fname);
    1120         124 :               debugdata->d_buf = memcpy (xmalloc (debugdata->d_size),
    1121             :                                          debugdata->d_buf, debugdata->d_size);
    1122             :             }
    1123             :         }
    1124             : 
    1125             :       /* Finish the ELF header.  Fill in the fields not handled by
    1126             :          libelf from the old file.  */
    1127          49 :       debugehdr = gelf_getehdr (debugelf, &debugehdr_mem);
    1128          49 :       if (debugehdr == NULL)
    1129           0 :         INTERNAL_ERROR (fname);
    1130             : 
    1131          98 :       memcpy (debugehdr->e_ident, ehdr->e_ident, EI_NIDENT);
    1132          49 :       debugehdr->e_type = ehdr->e_type;
    1133          49 :       debugehdr->e_machine = ehdr->e_machine;
    1134          49 :       debugehdr->e_version = ehdr->e_version;
    1135          49 :       debugehdr->e_entry = ehdr->e_entry;
    1136          49 :       debugehdr->e_flags = ehdr->e_flags;
    1137             : 
    1138             :       size_t shdrstrndx;
    1139          49 :       if (elf_getshdrstrndx (elf, &shdrstrndx) < 0)
    1140             :         {
    1141           0 :           error (0, 0, gettext ("%s: error while getting shdrstrndx: %s"),
    1142             :                  fname, elf_errmsg (-1));
    1143           0 :           result = 1;
    1144           0 :           goto fail_close;
    1145             :         }
    1146             : 
    1147          49 :       if (shstrndx < SHN_LORESERVE)
    1148          47 :         debugehdr->e_shstrndx = shdrstrndx;
    1149             :       else
    1150             :         {
    1151           2 :           debugehdr->e_shstrndx = SHN_XINDEX;
    1152           2 :           Elf_Scn *scn0 = elf_getscn (debugelf, 0);
    1153             :           GElf_Shdr shdr0_mem;
    1154           2 :           GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem);
    1155           2 :           if (shdr0 == NULL)
    1156             :             {
    1157           0 :               error (0, 0, gettext ("%s: error getting zero section: %s"),
    1158             :                      debug_fname, elf_errmsg (-1));
    1159           0 :               result = 1;
    1160           0 :               goto fail_close;
    1161             :             }
    1162             : 
    1163           2 :           shdr0->sh_link = shdrstrndx;
    1164           2 :           if (gelf_update_shdr (scn0, shdr0) == 0)
    1165             :             {
    1166           0 :               error (0, 0, gettext ("%s: error while updating zero section: %s"),
    1167             :                      debug_fname, elf_errmsg (-1));
    1168           0 :               result = 1;
    1169           0 :               goto fail_close;
    1170             :             }
    1171             : 
    1172             :         }
    1173             : 
    1174          49 :       if (unlikely (gelf_update_ehdr (debugelf, debugehdr) == 0))
    1175             :         {
    1176           0 :           error (0, 0, gettext ("%s: error while creating ELF header: %s"),
    1177             :                  debug_fname, elf_errmsg (-1));
    1178           0 :           result = 1;
    1179           0 :           goto fail_close;
    1180             :         }
    1181             :     }
    1182             : 
    1183             :   /* Although we always create a new section header string table we
    1184             :      don't explicitly mark the existing one as unused.  It can still
    1185             :      be used through a symbol table section we are keeping.  If not it
    1186             :      will already be marked as unused.  */
    1187             : 
    1188             :   /* We need a string table for the section headers.  */
    1189          85 :   shst = dwelf_strtab_init (true);
    1190          85 :   if (shst == NULL)
    1191             :     {
    1192           0 :       cleanup_debug ();
    1193           0 :       error (EXIT_FAILURE, errno, gettext ("while preparing output for '%s'"),
    1194           0 :              output_fname ?: fname);
    1195             :     }
    1196             : 
    1197             :   /* Assign new section numbers.  */
    1198          85 :   shdr_info[0].idx = 0;
    1199      199444 :   for (cnt = idx = 1; cnt < shnum; ++cnt)
    1200      199359 :     if (shdr_info[cnt].idx > 0)
    1201             :       {
    1202       67406 :         shdr_info[cnt].idx = idx++;
    1203             : 
    1204             :         /* Create a new section.  */
    1205       67406 :         shdr_info[cnt].newscn = elf_newscn (newelf);
    1206       67406 :         if (shdr_info[cnt].newscn == NULL)
    1207             :           {
    1208           0 :             cleanup_debug ();
    1209           0 :             error (EXIT_FAILURE, 0,
    1210           0 :                    gettext ("while generating output file: %s"),
    1211             :                    elf_errmsg (-1));
    1212             :           }
    1213             : 
    1214       67406 :         elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
    1215             : 
    1216             :         /* Add this name to the section header string table.  */
    1217       67406 :         shdr_info[cnt].se = dwelf_strtab_add (shst, shdr_info[cnt].name);
    1218             :       }
    1219             : 
    1220             :   /* Test whether we are doing anything at all.  Either all removable
    1221             :      sections are already gone.  Or the only section we would remove is
    1222             :      the .shstrtab section which we would add again.  */
    1223         255 :   bool removing_sections = !(cnt == idx
    1224          85 :                              || (cnt == idx + 1
    1225           4 :                                  && shdr_info[shstrndx].idx == 0));
    1226          85 :   if (output_fname == NULL && !removing_sections)
    1227             :       goto fail_close;
    1228             : 
    1229             :   /* Create the reference to the file with the debug info (if any).  */
    1230          83 :   if (debug_fname != NULL && !remove_shdrs && removing_sections)
    1231             :     {
    1232             :       /* Add the section header string table section name.  */
    1233          47 :       shdr_info[cnt].se = dwelf_strtab_add_len (shst, ".gnu_debuglink", 15);
    1234          47 :       shdr_info[cnt].idx = idx++;
    1235             : 
    1236             :       /* Create the section header.  */
    1237          47 :       shdr_info[cnt].shdr.sh_type = SHT_PROGBITS;
    1238          47 :       shdr_info[cnt].shdr.sh_flags = 0;
    1239          47 :       shdr_info[cnt].shdr.sh_addr = 0;
    1240          47 :       shdr_info[cnt].shdr.sh_link = SHN_UNDEF;
    1241          47 :       shdr_info[cnt].shdr.sh_info = SHN_UNDEF;
    1242          47 :       shdr_info[cnt].shdr.sh_entsize = 0;
    1243          47 :       shdr_info[cnt].shdr.sh_addralign = 4;
    1244             :       /* We set the offset to zero here.  Before we write the ELF file the
    1245             :          field must have the correct value.  This is done in the final
    1246             :          loop over all section.  Then we have all the information needed.  */
    1247          47 :       shdr_info[cnt].shdr.sh_offset = 0;
    1248             : 
    1249             :       /* Create the section.  */
    1250          47 :       shdr_info[cnt].newscn = elf_newscn (newelf);
    1251          47 :       if (shdr_info[cnt].newscn == NULL)
    1252             :         {
    1253           0 :           cleanup_debug ();
    1254           0 :           error (EXIT_FAILURE, 0,
    1255           0 :                  gettext ("while create section header section: %s"),
    1256             :                  elf_errmsg (-1));
    1257             :         }
    1258          47 :       elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
    1259             : 
    1260          47 :       shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn);
    1261          47 :       if (shdr_info[cnt].data == NULL)
    1262             :         {
    1263           0 :           cleanup_debug ();
    1264           0 :           error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"),
    1265             :                  elf_errmsg (-1));
    1266             :         }
    1267             : 
    1268          47 :       char *debug_basename = basename (debug_fname_embed ?: debug_fname);
    1269          47 :       off_t crc_offset = strlen (debug_basename) + 1;
    1270             :       /* Align to 4 byte boundary */
    1271          47 :       crc_offset = ((crc_offset - 1) & ~3) + 4;
    1272             : 
    1273          47 :       shdr_info[cnt].data->d_align = 4;
    1274          47 :       shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size
    1275          47 :         = crc_offset + 4;
    1276          47 :       debuglink_buf = xcalloc (1, shdr_info[cnt].data->d_size);
    1277          47 :       shdr_info[cnt].data->d_buf = debuglink_buf;
    1278             : 
    1279          94 :       strcpy (shdr_info[cnt].data->d_buf, debug_basename);
    1280             : 
    1281             :       /* Cache this Elf_Data describing the CRC32 word in the section.
    1282             :          We'll fill this in when we have written the debug file.  */
    1283          47 :       debuglink_crc_data = *shdr_info[cnt].data;
    1284          94 :       debuglink_crc_data.d_buf = ((char *) debuglink_crc_data.d_buf
    1285          47 :                                   + crc_offset);
    1286          47 :       debuglink_crc_data.d_size = 4;
    1287             : 
    1288             :       /* One more section done.  */
    1289          47 :       ++cnt;
    1290             :     }
    1291             : 
    1292             :   /* Index of the section header table in the shdr_info array.  */
    1293          83 :   shdridx = cnt;
    1294             : 
    1295             :   /* Add the section header string table section name.  */
    1296          83 :   shdr_info[cnt].se = dwelf_strtab_add_len (shst, ".shstrtab", 10);
    1297          83 :   shdr_info[cnt].idx = idx;
    1298             : 
    1299             :   /* Create the section header.  */
    1300          83 :   shdr_info[cnt].shdr.sh_type = SHT_STRTAB;
    1301          83 :   shdr_info[cnt].shdr.sh_flags = 0;
    1302          83 :   shdr_info[cnt].shdr.sh_addr = 0;
    1303          83 :   shdr_info[cnt].shdr.sh_link = SHN_UNDEF;
    1304          83 :   shdr_info[cnt].shdr.sh_info = SHN_UNDEF;
    1305          83 :   shdr_info[cnt].shdr.sh_entsize = 0;
    1306             :   /* We set the offset to zero here.  Before we write the ELF file the
    1307             :      field must have the correct value.  This is done in the final
    1308             :      loop over all section.  Then we have all the information needed.  */
    1309          83 :   shdr_info[cnt].shdr.sh_offset = 0;
    1310          83 :   shdr_info[cnt].shdr.sh_addralign = 1;
    1311             : 
    1312             :   /* Create the section.  */
    1313          83 :   shdr_info[cnt].newscn = elf_newscn (newelf);
    1314          83 :   if (shdr_info[cnt].newscn == NULL)
    1315             :     {
    1316           0 :       cleanup_debug ();
    1317           0 :       error (EXIT_FAILURE, 0,
    1318           0 :              gettext ("while create section header section: %s"),
    1319             :              elf_errmsg (-1));
    1320             :     }
    1321          83 :   elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == idx);
    1322             : 
    1323             :   /* Finalize the string table and fill in the correct indices in the
    1324             :      section headers.  */
    1325          83 :   shstrtab_data = elf_newdata (shdr_info[cnt].newscn);
    1326          83 :   if (shstrtab_data == NULL)
    1327             :     {
    1328           0 :       cleanup_debug ();
    1329           0 :       error (EXIT_FAILURE, 0,
    1330           0 :              gettext ("while create section header string table: %s"),
    1331             :              elf_errmsg (-1));
    1332             :     }
    1333          83 :   if (dwelf_strtab_finalize (shst, shstrtab_data) == NULL)
    1334             :     {
    1335           0 :       cleanup_debug ();
    1336             :       error (EXIT_FAILURE, 0,
    1337           0 :              gettext ("no memory to create section header string table"));
    1338             :     }
    1339             : 
    1340             :   /* We have to set the section size.  */
    1341          83 :   shdr_info[cnt].shdr.sh_size = shstrtab_data->d_size;
    1342             : 
    1343             :   /* Update the section information.  */
    1344          83 :   GElf_Off lastoffset = 0;
    1345      133980 :   for (cnt = 1; cnt <= shdridx; ++cnt)
    1346      133898 :     if (shdr_info[cnt].idx > 0)
    1347             :       {
    1348             :         Elf_Data *newdata;
    1349             : 
    1350        1948 :         scn = elf_getscn (newelf, shdr_info[cnt].idx);
    1351        1948 :         elf_assert (scn != NULL);
    1352             : 
    1353             :         /* Update the name.  */
    1354        1948 :         shdr_info[cnt].shdr.sh_name = dwelf_strent_off (shdr_info[cnt].se);
    1355             : 
    1356             :         /* Update the section header from the input file.  Some fields
    1357             :            might be section indeces which now have to be adjusted.  Keep
    1358             :            the index to the "current" sh_link in case we need it to lookup
    1359             :            symbol table names.  */
    1360        1948 :         size_t sh_link = shdr_info[cnt].shdr.sh_link;
    1361        1948 :         if (shdr_info[cnt].shdr.sh_link != 0)
    1362         561 :           shdr_info[cnt].shdr.sh_link =
    1363         561 :             shdr_info[shdr_info[cnt].shdr.sh_link].idx;
    1364             : 
    1365        1948 :         if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
    1366             :           {
    1367          10 :             elf_assert (shdr_info[cnt].data != NULL
    1368             :                         && shdr_info[cnt].data->d_buf != NULL);
    1369             : 
    1370             :             Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
    1371          19 :             for (size_t inner = 0;
    1372          19 :                  inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
    1373          14 :                  ++inner)
    1374          14 :               if (grpref[inner] < shnum)
    1375          14 :                 grpref[inner] = shdr_info[grpref[inner]].idx;
    1376             :               else
    1377             :                 goto illformed;
    1378             :           }
    1379             : 
    1380             :         /* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag.  */
    1381        1948 :         if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
    1382         249 :           shdr_info[cnt].shdr.sh_info =
    1383         249 :             shdr_info[shdr_info[cnt].shdr.sh_info].idx;
    1384             : 
    1385             :         /* Get the data from the old file if necessary.  We already
    1386             :            created the data for the section header string table.  */
    1387        1948 :         if (cnt < shnum)
    1388             :           {
    1389        1820 :             if (shdr_info[cnt].data == NULL)
    1390             :               {
    1391         774 :                 shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
    1392         774 :                 if (shdr_info[cnt].data == NULL)
    1393           0 :                   INTERNAL_ERROR (fname);
    1394             :               }
    1395             : 
    1396             :             /* Set the data.  This is done by copying from the old file.  */
    1397        1820 :             newdata = elf_newdata (scn);
    1398        1820 :             if (newdata == NULL)
    1399           0 :               INTERNAL_ERROR (fname);
    1400             : 
    1401             :             /* Copy the structure.  */
    1402        1820 :             *newdata = *shdr_info[cnt].data;
    1403             : 
    1404             :             /* We know the size.  */
    1405        1820 :             shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size;
    1406             : 
    1407             :             /* We have to adjust symbol tables.  The st_shndx member might
    1408             :                have to be updated.  */
    1409        3640 :             if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
    1410        1820 :                 || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
    1411             :               {
    1412          99 :                 Elf_Data *versiondata = NULL;
    1413          99 :                 Elf_Data *shndxdata = NULL;
    1414             : 
    1415          99 :                 size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
    1416             : 
    1417          99 :                 if (shdr_info[cnt].symtab_idx != 0)
    1418             :                   {
    1419           0 :                     elf_assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX);
    1420             :                     /* This section has extended section information.
    1421             :                        We have to modify that information, too.  */
    1422           0 :                     shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
    1423             :                                              NULL);
    1424             : 
    1425           0 :                     elf_assert (shndxdata != NULL
    1426             :                                 && shndxdata->d_buf != NULL
    1427             :                                 && ((shndxdata->d_size / sizeof (Elf32_Word))
    1428             :                                     >= shdr_info[cnt].data->d_size / elsize));
    1429             :                   }
    1430             : 
    1431          99 :                 if (shdr_info[cnt].version_idx != 0)
    1432             :                   {
    1433          50 :                     elf_assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM);
    1434             :                     /* This section has associated version
    1435             :                        information.  We have to modify that
    1436             :                        information, too.  */
    1437          50 :                     versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn,
    1438             :                                                NULL);
    1439             : 
    1440         150 :                     elf_assert (versiondata != NULL
    1441             :                                 && versiondata->d_buf != NULL
    1442             :                                 && ((versiondata->d_size / sizeof (GElf_Versym))
    1443             :                                     >= shdr_info[cnt].data->d_size / elsize));
    1444             :                   }
    1445             : 
    1446             :                 shdr_info[cnt].newsymidx
    1447          99 :                   = (Elf32_Word *) xcalloc (shdr_info[cnt].data->d_size
    1448             :                                             / elsize, sizeof (Elf32_Word));
    1449             : 
    1450          99 :                 bool last_was_local = true;
    1451             :                 size_t destidx;
    1452             :                 size_t inner;
    1453       18911 :                 for (destidx = inner = 1;
    1454       18812 :                      inner < shdr_info[cnt].data->d_size / elsize;
    1455       18713 :                      ++inner)
    1456             :                   {
    1457             :                     Elf32_Word sec;
    1458             :                     GElf_Sym sym_mem;
    1459             :                     Elf32_Word xshndx;
    1460       18714 :                     GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data,
    1461             :                                                       shndxdata, inner,
    1462             :                                                       &sym_mem, &xshndx);
    1463       18714 :                     if (sym == NULL)
    1464           0 :                       INTERNAL_ERROR (fname);
    1465             : 
    1466       18714 :                     if (sym->st_shndx == SHN_UNDEF
    1467       17121 :                         || (sym->st_shndx >= shnum
    1468         256 :                             && sym->st_shndx != SHN_XINDEX))
    1469             :                       {
    1470             :                         /* This is no section index, leave it alone
    1471             :                            unless it is moved.  */
    1472        1849 :                         if (destidx != inner
    1473        1362 :                             && gelf_update_symshndx (shdr_info[cnt].data,
    1474             :                                                      shndxdata,
    1475             :                                                      destidx, sym,
    1476             :                                                      xshndx) == 0)
    1477           0 :                           INTERNAL_ERROR (fname);
    1478             : 
    1479        1849 :                         shdr_info[cnt].newsymidx[inner] = destidx++;
    1480             : 
    1481        1849 :                         if (last_was_local
    1482         241 :                             && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
    1483             :                           {
    1484          59 :                             last_was_local = false;
    1485          59 :                             shdr_info[cnt].shdr.sh_info = destidx - 1;
    1486             :                           }
    1487             : 
    1488        1849 :                         continue;
    1489             :                       }
    1490             : 
    1491             :                     /* Get the full section index, if necessary from the
    1492             :                        XINDEX table.  */
    1493       16865 :                     if (sym->st_shndx == SHN_XINDEX)
    1494           0 :                       elf_assert (shndxdata != NULL
    1495             :                                   && shndxdata->d_buf != NULL);
    1496       16865 :                     size_t sidx = (sym->st_shndx != SHN_XINDEX
    1497       16865 :                                    ? sym->st_shndx : xshndx);
    1498       16865 :                     sec = shdr_info[sidx].idx;
    1499             : 
    1500       16865 :                     if (sec != 0)
    1501             :                       {
    1502             :                         GElf_Section nshndx;
    1503             :                         Elf32_Word nxshndx;
    1504             : 
    1505        2589 :                         if (sec < SHN_LORESERVE)
    1506             :                           {
    1507        2588 :                             nshndx = sec;
    1508        2588 :                             nxshndx = 0;
    1509             :                           }
    1510             :                         else
    1511             :                           {
    1512             :                             nshndx = SHN_XINDEX;
    1513             :                             nxshndx = sec;
    1514             :                           }
    1515             : 
    1516        2589 :                         elf_assert (sec < SHN_LORESERVE || shndxdata != NULL);
    1517             : 
    1518        2588 :                         if ((inner != destidx || nshndx != sym->st_shndx
    1519        1299 :                              || (shndxdata != NULL && nxshndx != xshndx))
    1520        2578 :                             && (sym->st_shndx = nshndx,
    1521        1289 :                                 gelf_update_symshndx (shdr_info[cnt].data,
    1522             :                                                       shndxdata,
    1523             :                                                       destidx, sym,
    1524             :                                                       nxshndx) == 0))
    1525           0 :                           INTERNAL_ERROR (fname);
    1526             : 
    1527        2588 :                         shdr_info[cnt].newsymidx[inner] = destidx++;
    1528             : 
    1529        2588 :                         if (last_was_local
    1530        2172 :                             && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
    1531             :                           {
    1532          39 :                             last_was_local = false;
    1533          39 :                             shdr_info[cnt].shdr.sh_info = destidx - 1;
    1534             :                           }
    1535             :                       }
    1536       14276 :                     else if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0
    1537          48 :                              && GELF_ST_TYPE (sym->st_info) != STT_SECTION
    1538           0 :                              && shdr_info[sidx].shdr.sh_type != SHT_GROUP)
    1539             :                       {
    1540             :                         /* Removing a real symbol from an allocated
    1541             :                            symbol table is hard and probably a
    1542             :                            mistake.  Really removing it means
    1543             :                            rewriting the dynamic segment and hash
    1544             :                            sections.  Just warn and set the symbol
    1545             :                            section to UNDEF.  */
    1546           0 :                         error (0, 0,
    1547           0 :                                gettext ("Cannot remove symbol [%zd] from allocated symbol table [%zd]"), inner, cnt);
    1548           0 :                         sym->st_shndx = SHN_UNDEF;
    1549           0 :                         if (gelf_update_sym (shdr_info[cnt].data, destidx,
    1550             :                                              sym) == 0)
    1551           0 :                           INTERNAL_ERROR (fname);
    1552           0 :                         shdr_info[cnt].newsymidx[inner] = destidx++;
    1553             :                       }
    1554       14276 :                     else if (debug_fname != NULL
    1555       14098 :                              && shdr_info[cnt].debug_data == NULL)
    1556             :                       /* The symbol points to a section that is discarded
    1557             :                          but isn't preserved in the debug file. Check that
    1558             :                          this is a section or group signature symbol
    1559             :                          for a section which has been removed.  Or a special
    1560             :                          data marker symbol to a debug section.  */
    1561             :                       {
    1562          50 :                         elf_assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION
    1563             :                                     || ((shdr_info[sidx].shdr.sh_type
    1564             :                                          == SHT_GROUP)
    1565             :                                         && (shdr_info[sidx].shdr.sh_info
    1566             :                                             == inner))
    1567             :                                     || ebl_data_marker_symbol (ebl, sym,
    1568             :                                                 elf_strptr (elf, sh_link,
    1569             :                                                             sym->st_name)));
    1570             :                       }
    1571             :                   }
    1572             : 
    1573          98 :                 if (destidx != inner)
    1574             :                   {
    1575             :                     /* The size of the symbol table changed.  */
    1576          54 :                     shdr_info[cnt].shdr.sh_size = newdata->d_size
    1577          54 :                       = destidx * elsize;
    1578          54 :                     any_symtab_changes = true;
    1579             :                   }
    1580             :                 else
    1581             :                   {
    1582             :                     /* The symbol table didn't really change.  */
    1583          44 :                     free (shdr_info[cnt].newsymidx);
    1584          44 :                     shdr_info[cnt].newsymidx = NULL;
    1585             :                   }
    1586             :               }
    1587             :           }
    1588             : 
    1589             :         /* If we have to, compute the offset of the section.
    1590             :            If allocate and unallocated sections are mixed, we only update
    1591             :            the allocated ones now.  The unallocated ones come second.  */
    1592        1947 :         if (! mixed_allocated_unallocated
    1593         860 :             || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0)
    1594             :           {
    1595        1583 :             if (shdr_info[cnt].shdr.sh_offset == 0)
    1596             :               shdr_info[cnt].shdr.sh_offset
    1597         876 :                 = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
    1598         438 :                    & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
    1599             : 
    1600             :             /* Set the section header in the new file.  */
    1601        1583 :             if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
    1602             :               /* There cannot be any overflows.  */
    1603           0 :               INTERNAL_ERROR (fname);
    1604             : 
    1605             :             /* Remember the last section written so far.  */
    1606        3166 :             GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
    1607        1583 :                                ? shdr_info[cnt].shdr.sh_size : 0);
    1608        1583 :             if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
    1609        1484 :               lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
    1610             :           }
    1611             :       }
    1612             : 
    1613             :   /* We might have to update the unallocated sections after we done the
    1614             :      allocated ones.  lastoffset is set to right after the last allocated
    1615             :      section.  */
    1616          82 :   if (mixed_allocated_unallocated)
    1617      132483 :     for (cnt = 1; cnt <= shdridx; ++cnt)
    1618      132441 :       if (shdr_info[cnt].idx > 0)
    1619             :         {
    1620         835 :           scn = elf_getscn (newelf, shdr_info[cnt].idx);
    1621         835 :           if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
    1622             :             {
    1623         360 :               if (shdr_info[cnt].shdr.sh_offset == 0)
    1624             :                 shdr_info[cnt].shdr.sh_offset
    1625         720 :                   = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
    1626         360 :                      & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
    1627             : 
    1628             :               /* Set the section header in the new file.  */
    1629         360 :               if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
    1630             :                 /* There cannot be any overflows.  */
    1631           0 :                 INTERNAL_ERROR (fname);
    1632             : 
    1633             :               /* Remember the last section written so far.  */
    1634         720 :               GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
    1635         360 :                                  ? shdr_info[cnt].shdr.sh_size : 0);
    1636         360 :               if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
    1637         357 :                 lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
    1638             :             }
    1639             :         }
    1640             : 
    1641             :   /* Adjust symbol references if symbol tables changed.  */
    1642          82 :   if (any_symtab_changes)
    1643             :     /* Find all relocation sections which use this symbol table.  */
    1644        1807 :     for (cnt = 1; cnt <= shdridx; ++cnt)
    1645             :       {
    1646             :         /* Update section headers when the data size has changed.
    1647             :            We also update the SHT_NOBITS section in the debug
    1648             :            file so that the section headers match in sh_size.  */
    1649          12 :         inline void update_section_size (const Elf_Data *newdata)
    1650             :         {
    1651             :           GElf_Shdr shdr_mem;
    1652          12 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1653          12 :           shdr->sh_size = newdata->d_size;
    1654          12 :           (void) gelf_update_shdr (scn, shdr);
    1655          12 :           if (debugelf != NULL)
    1656             :             {
    1657             :               /* libelf will use d_size to set sh_size.  */
    1658           2 :               Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf,
    1659             :                                                              cnt), NULL);
    1660           2 :               if (debugdata == NULL)
    1661           0 :                 INTERNAL_ERROR (fname);
    1662           2 :               debugdata->d_size = newdata->d_size;
    1663             :             }
    1664          12 :         }
    1665             : 
    1666        1755 :         if (shdr_info[cnt].idx == 0 && debug_fname == NULL)
    1667             :           /* Ignore sections which are discarded.  When we are saving a
    1668             :              relocation section in a separate debug file, we must fix up
    1669             :              the symbol table references.  */
    1670         211 :           continue;
    1671             : 
    1672        1544 :         const Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
    1673        1544 :         elf_assert (symtabidx < shnum + 2);
    1674        1544 :         const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx;
    1675        1544 :         switch (shdr_info[cnt].shdr.sh_type)
    1676             :           {
    1677             :             inline bool no_symtab_updates (void)
    1678             :             {
    1679             :               /* If the symbol table hasn't changed, do not do anything.  */
    1680         356 :               if (shdr_info[symtabidx].newsymidx == NULL)
    1681             :                 return true;
    1682             : 
    1683             :               /* If the symbol table is not discarded, but additionally
    1684             :                  duplicated in the separate debug file and this section
    1685             :                  is discarded, don't adjust anything.  */
    1686             :               return (shdr_info[cnt].idx == 0
    1687         313 :                       && shdr_info[symtabidx].debug_data != NULL);
    1688             :             }
    1689             : 
    1690             :           case SHT_REL:
    1691             :           case SHT_RELA:
    1692         295 :             if (no_symtab_updates ())
    1693             :               break;
    1694             : 
    1695         334 :             Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0
    1696             :                                        ? elf_getscn (debugelf, cnt)
    1697         167 :                                        : elf_getscn (newelf,
    1698             :                                                      shdr_info[cnt].idx),
    1699             :                                        NULL);
    1700         167 :             elf_assert (d != NULL && d->d_buf != NULL
    1701             :                         && shdr_info[cnt].shdr.sh_entsize != 0);
    1702         167 :             size_t nrels = (shdr_info[cnt].shdr.sh_size
    1703             :                             / shdr_info[cnt].shdr.sh_entsize);
    1704             : 
    1705         167 :             size_t symsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
    1706         334 :             const Elf32_Word symidxn = (shdr_info[symtabidx].data->d_size
    1707         167 :                                         / symsize);
    1708         167 :             if (shdr_info[cnt].shdr.sh_type == SHT_REL)
    1709        2411 :               for (size_t relidx = 0; relidx < nrels; ++relidx)
    1710             :                 {
    1711             :                   GElf_Rel rel_mem;
    1712        2411 :                   if (gelf_getrel (d, relidx, &rel_mem) == NULL)
    1713           0 :                     INTERNAL_ERROR (fname);
    1714             : 
    1715        2411 :                   size_t symidx = GELF_R_SYM (rel_mem.r_info);
    1716        2411 :                   elf_assert (symidx < symidxn);
    1717        2411 :                   if (newsymidx[symidx] != symidx)
    1718             :                     {
    1719             :                       rel_mem.r_info
    1720        2206 :                         = GELF_R_INFO (newsymidx[symidx],
    1721             :                                        GELF_R_TYPE (rel_mem.r_info));
    1722             : 
    1723        2206 :                       if (gelf_update_rel (d, relidx, &rel_mem) == 0)
    1724           0 :                         INTERNAL_ERROR (fname);
    1725             :                     }
    1726             :                 }
    1727             :             else
    1728       11082 :               for (size_t relidx = 0; relidx < nrels; ++relidx)
    1729             :                 {
    1730             :                   GElf_Rela rel_mem;
    1731       11082 :                   if (gelf_getrela (d, relidx, &rel_mem) == NULL)
    1732           0 :                     INTERNAL_ERROR (fname);
    1733             : 
    1734       11082 :                   size_t symidx = GELF_R_SYM (rel_mem.r_info);
    1735       11082 :                   elf_assert (symidx < symidxn);
    1736       11082 :                   if (newsymidx[symidx] != symidx)
    1737             :                     {
    1738             :                       rel_mem.r_info
    1739        3632 :                         = GELF_R_INFO (newsymidx[symidx],
    1740             :                                        GELF_R_TYPE (rel_mem.r_info));
    1741             : 
    1742        3632 :                       if (gelf_update_rela (d, relidx, &rel_mem) == 0)
    1743           0 :                         INTERNAL_ERROR (fname);
    1744             :                     }
    1745             :                 }
    1746             :             break;
    1747             : 
    1748             :           case SHT_HASH:
    1749           6 :             if (no_symtab_updates ())
    1750             :               break;
    1751             : 
    1752             :             /* We have to recompute the hash table.  */
    1753             : 
    1754           6 :             elf_assert (shdr_info[cnt].idx > 0);
    1755             : 
    1756             :             /* The hash section in the new file.  */
    1757           6 :             scn = elf_getscn (newelf, shdr_info[cnt].idx);
    1758             : 
    1759             :             /* The symbol table data.  */
    1760           6 :             Elf_Data *symd = elf_getdata (elf_getscn (newelf,
    1761           6 :                                                       shdr_info[symtabidx].idx),
    1762             :                                           NULL);
    1763           6 :             elf_assert (symd != NULL && symd->d_buf != NULL);
    1764             : 
    1765             :             /* The hash table data.  */
    1766           6 :             Elf_Data *hashd = elf_getdata (scn, NULL);
    1767           6 :             elf_assert (hashd != NULL && hashd->d_buf != NULL);
    1768             : 
    1769           6 :             if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word))
    1770             :               {
    1771             :                 /* Sane arches first.  */
    1772           6 :                 elf_assert (hashd->d_size >= 2 * sizeof (Elf32_Word));
    1773           6 :                 Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf;
    1774             : 
    1775           6 :                 size_t strshndx = shdr_info[symtabidx].old_sh_link;
    1776           6 :                 size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
    1777             : 
    1778           6 :                 Elf32_Word nchain = bucket[1];
    1779           6 :                 Elf32_Word nbucket = bucket[0];
    1780          12 :                 uint64_t used_buf = ((2ULL + nchain + nbucket)
    1781           6 :                                      * sizeof (Elf32_Word));
    1782           6 :                 elf_assert (used_buf <= hashd->d_size);
    1783             : 
    1784             :                 /* Adjust the nchain value.  The symbol table size
    1785             :                    changed.  We keep the same size for the bucket array.  */
    1786           6 :                 bucket[1] = symd->d_size / elsize;
    1787           6 :                 bucket += 2;
    1788           6 :                 Elf32_Word *chain = bucket + nbucket;
    1789             : 
    1790             :                 /* New size of the section.  */
    1791          12 :                 size_t n_size = ((2 + symd->d_size / elsize + nbucket)
    1792           6 :                                  * sizeof (Elf32_Word));
    1793           6 :                 elf_assert (n_size <= hashd->d_size);
    1794           6 :                 hashd->d_size = n_size;
    1795           6 :                 update_section_size (hashd);
    1796             : 
    1797             :                 /* Clear the arrays.  */
    1798          12 :                 memset (bucket, '\0',
    1799           6 :                         (symd->d_size / elsize + nbucket)
    1800             :                         * sizeof (Elf32_Word));
    1801             : 
    1802          84 :                 for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
    1803          72 :                      inner < symd->d_size / elsize; ++inner)
    1804             :                   {
    1805             :                     GElf_Sym sym_mem;
    1806          72 :                     GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
    1807          72 :                     elf_assert (sym != NULL);
    1808             : 
    1809          72 :                     const char *name = elf_strptr (elf, strshndx,
    1810          72 :                                                    sym->st_name);
    1811          72 :                     elf_assert (name != NULL && nbucket != 0);
    1812          72 :                     size_t hidx = elf_hash (name) % nbucket;
    1813             : 
    1814          72 :                     if (bucket[hidx] == 0)
    1815          60 :                       bucket[hidx] = inner;
    1816             :                     else
    1817             :                       {
    1818          12 :                         hidx = bucket[hidx];
    1819             : 
    1820          24 :                         while (chain[hidx] != 0 && chain[hidx] < nchain)
    1821           0 :                           hidx = chain[hidx];
    1822             : 
    1823          12 :                         chain[hidx] = inner;
    1824             :                       }
    1825             :                   }
    1826             :               }
    1827             :             else
    1828           0 :               {
    1829             :                 /* Alpha and S390 64-bit use 64-bit SHT_HASH entries.  */
    1830           0 :                 elf_assert (shdr_info[cnt].shdr.sh_entsize
    1831             :                             == sizeof (Elf64_Xword));
    1832             : 
    1833           0 :                 Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf;
    1834             : 
    1835           0 :                 size_t strshndx = shdr_info[symtabidx].old_sh_link;
    1836           0 :                 size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
    1837             : 
    1838           0 :                 elf_assert (symd->d_size >= 2 * sizeof (Elf64_Xword));
    1839           0 :                 Elf64_Xword nbucket = bucket[0];
    1840           0 :                 Elf64_Xword nchain = bucket[1];
    1841           0 :                 uint64_t maxwords = hashd->d_size / sizeof (Elf64_Xword);
    1842           0 :                 elf_assert (maxwords >= 2
    1843             :                             && maxwords - 2 >= nbucket
    1844             :                             && maxwords - 2 - nbucket >= nchain);
    1845             : 
    1846             :                 /* Adjust the nchain value.  The symbol table size
    1847             :                    changed.  We keep the same size for the bucket array.  */
    1848           0 :                 bucket[1] = symd->d_size / elsize;
    1849           0 :                 bucket += 2;
    1850           0 :                 Elf64_Xword *chain = bucket + nbucket;
    1851             : 
    1852             :                 /* New size of the section.  */
    1853           0 :                 size_t n_size = ((2 + symd->d_size / elsize + nbucket)
    1854           0 :                                  * sizeof (Elf64_Xword));
    1855           0 :                 elf_assert (n_size <= hashd->d_size);
    1856           0 :                 hashd->d_size = n_size;
    1857           0 :                 update_section_size (hashd);
    1858             : 
    1859             :                 /* Clear the arrays.  */
    1860           0 :                 memset (bucket, '\0',
    1861           0 :                         (symd->d_size / elsize + nbucket)
    1862             :                         * sizeof (Elf64_Xword));
    1863             : 
    1864           0 :                 for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
    1865           0 :                      inner < symd->d_size / elsize; ++inner)
    1866             :                   {
    1867             :                     GElf_Sym sym_mem;
    1868           0 :                     GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
    1869           0 :                     elf_assert (sym != NULL);
    1870             : 
    1871           0 :                     const char *name = elf_strptr (elf, strshndx,
    1872           0 :                                                    sym->st_name);
    1873           0 :                     elf_assert (name != NULL && nbucket != 0);
    1874           0 :                     size_t hidx = elf_hash (name) % nbucket;
    1875             : 
    1876           0 :                     if (bucket[hidx] == 0)
    1877           0 :                       bucket[hidx] = inner;
    1878             :                     else
    1879             :                       {
    1880             :                         hidx = bucket[hidx];
    1881             : 
    1882           0 :                         while (chain[hidx] != 0 && chain[hidx] < nchain)
    1883             :                           hidx = chain[hidx];
    1884             : 
    1885           0 :                         chain[hidx] = inner;
    1886             :                       }
    1887             :                   }
    1888             :               }
    1889             :             break;
    1890             : 
    1891             :           case SHT_GNU_versym:
    1892             :             /* If the symbol table changed we have to adjust the entries.  */
    1893           6 :             if (no_symtab_updates ())
    1894             :               break;
    1895             : 
    1896           6 :             elf_assert (shdr_info[cnt].idx > 0);
    1897             : 
    1898             :             /* The symbol version section in the new file.  */
    1899           6 :             scn = elf_getscn (newelf, shdr_info[cnt].idx);
    1900             : 
    1901             :             /* The symbol table data.  */
    1902           6 :             symd = elf_getdata (elf_getscn (newelf, shdr_info[symtabidx].idx),
    1903             :                                 NULL);
    1904           6 :             elf_assert (symd != NULL && symd->d_buf != NULL);
    1905           6 :             size_t symz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
    1906           6 :             const Elf32_Word syms = (shdr_info[symtabidx].data->d_size / symz);
    1907             : 
    1908             :             /* The version symbol data.  */
    1909           6 :             Elf_Data *verd = elf_getdata (scn, NULL);
    1910           6 :             elf_assert (verd != NULL && verd->d_buf != NULL);
    1911             : 
    1912             :             /* The symbol version array.  */
    1913           6 :             GElf_Half *verstab = (GElf_Half *) verd->d_buf;
    1914             : 
    1915             :             /* Walk through the list and */
    1916           6 :             size_t elsize = gelf_fsize (elf, verd->d_type, 1, EV_CURRENT);
    1917           6 :             Elf32_Word vers = verd->d_size / elsize;
    1918         258 :             for (size_t inner = 1; inner < vers && inner < syms; ++inner)
    1919         252 :               if (newsymidx[inner] != 0 && newsymidx[inner] < vers)
    1920             :                 /* Overwriting the same array works since the
    1921             :                    reordering can only move entries to lower indices
    1922             :                    in the array.  */
    1923         204 :                 verstab[newsymidx[inner]] = verstab[inner];
    1924             : 
    1925             :             /* New size of the section.  */
    1926           6 :             verd->d_size = gelf_fsize (newelf, verd->d_type,
    1927           6 :                                        symd->d_size
    1928           6 :                                        / gelf_fsize (elf, symd->d_type, 1,
    1929             :                                                      EV_CURRENT),
    1930             :                                        EV_CURRENT);
    1931           6 :             update_section_size (verd);
    1932           6 :             break;
    1933             : 
    1934             :           case SHT_GROUP:
    1935           6 :             if (no_symtab_updates ())
    1936             :               break;
    1937             : 
    1938             :             /* Yes, the symbol table changed.
    1939             :                Update the section header of the section group.  */
    1940           5 :             scn = elf_getscn (newelf, shdr_info[cnt].idx);
    1941             :             GElf_Shdr shdr_mem;
    1942           5 :             GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1943           5 :             elf_assert (shdr != NULL);
    1944             : 
    1945           5 :             size_t symsz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
    1946          10 :             const Elf32_Word symn = (shdr_info[symtabidx].data->d_size
    1947           5 :                                      / symsz);
    1948           5 :             elf_assert (shdr->sh_info < symn);
    1949           5 :             shdr->sh_info = newsymidx[shdr->sh_info];
    1950             : 
    1951           5 :             (void) gelf_update_shdr (scn, shdr);
    1952           5 :             break;
    1953             :           }
    1954             :       }
    1955             : 
    1956             :   /* Remove any relocations between debug sections in ET_REL
    1957             :      for the debug file when requested.  These relocations are always
    1958             :      zero based between the unallocated sections.  */
    1959          82 :   if (debug_fname != NULL && removing_sections
    1960          46 :       && reloc_debug && ehdr->e_type == ET_REL)
    1961             :     {
    1962          10 :       scn = NULL;
    1963          10 :       cnt = 0;
    1964         360 :       while ((scn = elf_nextscn (debugelf, scn)) != NULL)
    1965             :         {
    1966         340 :           cnt++;
    1967             :           /* We need the actual section and header from the debugelf
    1968             :              not just the cached original in shdr_info because we
    1969             :              might want to change the size.  */
    1970             :           GElf_Shdr shdr_mem;
    1971         340 :           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1972         340 :           if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
    1973             :             {
    1974             :               /* Make sure that this relocation section points to a
    1975             :                  section to relocate with contents, that isn't
    1976             :                  allocated and that is a debug section.  */
    1977          49 :               Elf_Scn *tscn = elf_getscn (debugelf, shdr->sh_info);
    1978             :               GElf_Shdr tshdr_mem;
    1979          49 :               GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
    1980          49 :               if (tshdr->sh_type == SHT_NOBITS
    1981          49 :                   || tshdr->sh_size == 0
    1982          49 :                   || (tshdr->sh_flags & SHF_ALLOC) != 0)
    1983           0 :                 continue;
    1984             : 
    1985          49 :               const char *tname =  elf_strptr (debugelf, shstrndx,
    1986          49 :                                                tshdr->sh_name);
    1987          49 :               if (! tname || ! ebl_debugscn_p (ebl, tname))
    1988           0 :                 continue;
    1989             : 
    1990             :               /* OK, lets relocate all trivial cross debug section
    1991             :                  relocations. */
    1992          49 :               Elf_Data *reldata = elf_getdata (scn, NULL);
    1993          49 :               if (reldata == NULL || reldata->d_buf == NULL)
    1994           0 :                 INTERNAL_ERROR (fname);
    1995             : 
    1996             :               /* Make sure we adjust the uncompressed debug data
    1997             :                  (and recompress if necessary at the end).  */
    1998             :               GElf_Chdr tchdr;
    1999          49 :               int tcompress_type = 0;
    2000          49 :               if (gelf_getchdr (tscn, &tchdr) != NULL)
    2001             :                 {
    2002           5 :                   tcompress_type = tchdr.ch_type;
    2003           5 :                   if (elf_compress (tscn, 0, 0) != 1)
    2004           0 :                     INTERNAL_ERROR (fname);
    2005             :                 }
    2006             : 
    2007          49 :               Elf_Data *tdata = elf_getdata (tscn, NULL);
    2008          49 :               if (tdata == NULL || tdata->d_buf == NULL
    2009          49 :                   || tdata->d_type != ELF_T_BYTE)
    2010           0 :                 INTERNAL_ERROR (fname);
    2011             : 
    2012             :               /* Pick up the symbol table and shndx table to
    2013             :                  resolve relocation symbol indexes.  */
    2014          49 :               Elf64_Word symt = shdr->sh_link;
    2015             :               Elf_Data *symdata, *xndxdata;
    2016          49 :               elf_assert (symt < shnum + 2);
    2017          49 :               elf_assert (shdr_info[symt].symtab_idx < shnum + 2);
    2018          98 :               symdata = (shdr_info[symt].debug_data
    2019          49 :                          ?: shdr_info[symt].data);
    2020          98 :               xndxdata = (shdr_info[shdr_info[symt].symtab_idx].debug_data
    2021          49 :                           ?: shdr_info[shdr_info[symt].symtab_idx].data);
    2022             : 
    2023             :               /* Apply one relocation.  Returns true when trivial
    2024             :                  relocation actually done.  */
    2025       34747 :               bool relocate (GElf_Addr offset, const GElf_Sxword addend,
    2026             :                              bool is_rela, int rtype, int symndx)
    2027             :               {
    2028             :                 /* R_*_NONE relocs can always just be removed.  */
    2029       34747 :                 if (rtype == 0)
    2030             :                   return true;
    2031             : 
    2032             :                 /* We only do simple absolute relocations.  */
    2033       34747 :                 Elf_Type type = ebl_reloc_simple_type (ebl, rtype);
    2034       34747 :                 if (type == ELF_T_NUM)
    2035             :                   return false;
    2036             : 
    2037             :                 /* These are the types we can relocate.  */
    2038             : #define TYPES   DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half);             \
    2039             :                 DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword);           \
    2040             :                 DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
    2041             : 
    2042             :                 /* And only for relocations against other debug sections.  */
    2043             :                 GElf_Sym sym_mem;
    2044             :                 Elf32_Word xndx;
    2045       34709 :                 GElf_Sym *sym = gelf_getsymshndx (symdata, xndxdata,
    2046             :                                                   symndx, &sym_mem,
    2047             :                                                   &xndx);
    2048       69418 :                 Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
    2049       34709 :                                   ? xndx : sym->st_shndx);
    2050       34709 :                 if (sec >= shnum + 2)
    2051           0 :                   INTERNAL_ERROR (fname);
    2052             : 
    2053       34709 :                 if (ebl_debugscn_p (ebl, shdr_info[sec].name))
    2054             :                   {
    2055             :                     size_t size;
    2056             : 
    2057             : #define DO_TYPE(NAME, Name) GElf_##Name Name;
    2058             :                     union { TYPES; } tmpbuf;
    2059             : #undef DO_TYPE
    2060             : 
    2061       24096 :                     switch (type)
    2062             :                       {
    2063             : #define DO_TYPE(NAME, Name)                             \
    2064             :                         case ELF_T_##NAME:              \
    2065             :                           size = sizeof (GElf_##Name);  \
    2066             :                           tmpbuf.Name = 0;              \
    2067             :                           break;
    2068           0 :                         TYPES;
    2069             : #undef DO_TYPE
    2070             :                       default:
    2071             :                         return false;
    2072             :                       }
    2073             : 
    2074       24096 :                     if (offset > tdata->d_size
    2075       24096 :                         || tdata->d_size - offset < size)
    2076             :                       {
    2077           0 :                         cleanup_debug ();
    2078           0 :                         error (EXIT_FAILURE, 0, gettext ("bad relocation"));
    2079             :                       }
    2080             : 
    2081             :                     /* When the symbol value is zero then for SHT_REL
    2082             :                        sections this is all that needs to be checked.
    2083             :                        The addend is contained in the original data at
    2084             :                        the offset already.  So if the (section) symbol
    2085             :                        address is zero and the given addend is zero
    2086             :                        just remove the relocation, it isn't needed
    2087             :                        anymore.  */
    2088       24096 :                     if (addend == 0 && sym->st_value == 0)
    2089             :                       return true;
    2090             : 
    2091       20848 :                     Elf_Data tmpdata =
    2092             :                       {
    2093             :                         .d_type = type,
    2094             :                         .d_buf = &tmpbuf,
    2095             :                         .d_size = size,
    2096             :                         .d_version = EV_CURRENT,
    2097             :                       };
    2098       41696 :                     Elf_Data rdata =
    2099             :                       {
    2100             :                         .d_type = type,
    2101       20848 :                         .d_buf = tdata->d_buf + offset,
    2102             :                         .d_size = size,
    2103             :                         .d_version = EV_CURRENT,
    2104             :                       };
    2105             : 
    2106       20848 :                     GElf_Addr value = sym->st_value;
    2107       20848 :                     if (is_rela)
    2108             :                       {
    2109             :                         /* For SHT_RELA sections we just take the
    2110             :                            given addend and add it to the value.  */
    2111       20848 :                         value += addend;
    2112             :                       }
    2113             :                     else
    2114             :                       {
    2115             :                         /* For SHT_REL sections we have to peek at
    2116             :                            what is already in the section at the given
    2117             :                            offset to get the addend.  */
    2118           0 :                         Elf_Data *d = gelf_xlatetom (debugelf, &tmpdata,
    2119             :                                                      &rdata,
    2120           0 :                                                      ehdr->e_ident[EI_DATA]);
    2121           0 :                         if (d == NULL)
    2122           0 :                           INTERNAL_ERROR (fname);
    2123           0 :                         assert (d == &tmpdata);
    2124             :                       }
    2125             : 
    2126       20848 :                     switch (type)
    2127             :                       {
    2128             : #define DO_TYPE(NAME, Name)                                     \
    2129             :                         case ELF_T_##NAME:                      \
    2130             :                           tmpbuf.Name += (GElf_##Name) value;   \
    2131             :                           break;
    2132           0 :                         TYPES;
    2133             : #undef DO_TYPE
    2134           0 :                       default:
    2135           0 :                         abort ();
    2136             :                       }
    2137             : 
    2138             :                     /* Now finally put in the new value.  */
    2139       20848 :                     Elf_Data *s = gelf_xlatetof (debugelf, &rdata,
    2140             :                                                  &tmpdata,
    2141       20848 :                                                  ehdr->e_ident[EI_DATA]);
    2142       20848 :                     if (s == NULL)
    2143           0 :                       INTERNAL_ERROR (fname);
    2144       20848 :                     assert (s == &rdata);
    2145             : 
    2146             :                     return true;
    2147             :                   }
    2148             :                 return false;
    2149             :               }
    2150             : 
    2151          49 :               if (shdr->sh_entsize == 0)
    2152           0 :                 INTERNAL_ERROR (fname);
    2153             : 
    2154          49 :               size_t nrels = shdr->sh_size / shdr->sh_entsize;
    2155          49 :               size_t next = 0;
    2156          49 :               if (shdr->sh_type == SHT_REL)
    2157        3212 :                 for (size_t relidx = 0; relidx < nrels; ++relidx)
    2158             :                   {
    2159             :                     GElf_Rel rel_mem;
    2160        3212 :                     GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
    2161        3212 :                     if (! relocate (r->r_offset, 0, false,
    2162             :                                     GELF_R_TYPE (r->r_info),
    2163        3212 :                                     GELF_R_SYM (r->r_info)))
    2164             :                       {
    2165          18 :                         if (relidx != next)
    2166          16 :                           gelf_update_rel (reldata, next, r);
    2167          18 :                         ++next;
    2168             :                       }
    2169             :                   }
    2170             :               else
    2171       31535 :                 for (size_t relidx = 0; relidx < nrels; ++relidx)
    2172             :                   {
    2173             :                     GElf_Rela rela_mem;
    2174       31535 :                     GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
    2175       31535 :                     if (! relocate (r->r_offset, r->r_addend, true,
    2176             :                                     GELF_R_TYPE (r->r_info),
    2177       31535 :                                     GELF_R_SYM (r->r_info)))
    2178             :                       {
    2179       10633 :                         if (relidx != next)
    2180        5712 :                           gelf_update_rela (reldata, next, r);
    2181       10633 :                         ++next;
    2182             :                       }
    2183             :                   }
    2184             : 
    2185          49 :               nrels = next;
    2186          49 :               shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
    2187          49 :               gelf_update_shdr (scn, shdr);
    2188             : 
    2189          49 :               if (tcompress_type != 0)
    2190           5 :                 if (elf_compress (tscn, tcompress_type, ELF_CHF_FORCE) != 1)
    2191           0 :                   INTERNAL_ERROR (fname);
    2192             :             }
    2193             :         }
    2194             :     }
    2195             : 
    2196             :   /* Now that we have done all adjustments to the data,
    2197             :      we can actually write out the debug file.  */
    2198          82 :   if (debug_fname != NULL && removing_sections)
    2199             :     {
    2200             :       /* Finally write the file.  */
    2201          46 :       if (unlikely (elf_update (debugelf, ELF_C_WRITE) == -1))
    2202             :         {
    2203           0 :           error (0, 0, gettext ("while writing '%s': %s"),
    2204             :                  tmp_debug_fname, elf_errmsg (-1));
    2205           0 :           result = 1;
    2206           0 :           goto fail_close;
    2207             :         }
    2208             : 
    2209             :       /* Create the real output file.  First rename, then change the
    2210             :          mode.  */
    2211          46 :       if (rename (tmp_debug_fname, debug_fname) != 0
    2212          46 :           || fchmod (debug_fd, mode) != 0)
    2213             :         {
    2214           0 :           error (0, errno, gettext ("while creating '%s'"), debug_fname);
    2215           0 :           result = 1;
    2216           0 :           goto fail_close;
    2217             :         }
    2218             : 
    2219             :       /* The temporary file does not exist anymore.  */
    2220          46 :       free (tmp_debug_fname);
    2221          46 :       tmp_debug_fname = NULL;
    2222             : 
    2223          46 :       if (!remove_shdrs)
    2224             :         {
    2225             :           uint32_t debug_crc;
    2226          46 :           Elf_Data debug_crc_data =
    2227             :             {
    2228             :               .d_type = ELF_T_WORD,
    2229             :               .d_buf = &debug_crc,
    2230             :               .d_size = sizeof (debug_crc),
    2231             :               .d_version = EV_CURRENT
    2232             :             };
    2233             : 
    2234             :           /* Compute the checksum which we will add to the executable.  */
    2235          46 :           if (crc32_file (debug_fd, &debug_crc) != 0)
    2236             :             {
    2237           0 :               error (0, errno, gettext ("\
    2238             : while computing checksum for debug information"));
    2239           0 :               unlink (debug_fname);
    2240           0 :               result = 1;
    2241           0 :               goto fail_close;
    2242             :             }
    2243             : 
    2244             :           /* Store it in the debuglink section data.  */
    2245          46 :           if (unlikely (gelf_xlatetof (newelf, &debuglink_crc_data,
    2246             :                                        &debug_crc_data, ehdr->e_ident[EI_DATA])
    2247             :                         != &debuglink_crc_data))
    2248           0 :             INTERNAL_ERROR (fname);
    2249             :         }
    2250             :     }
    2251             : 
    2252             :   /* Finally finish the ELF header.  Fill in the fields not handled by
    2253             :      libelf from the old file.  */
    2254          82 :   newehdr = gelf_getehdr (newelf, &newehdr_mem);
    2255          82 :   if (newehdr == NULL)
    2256           0 :     INTERNAL_ERROR (fname);
    2257             : 
    2258         164 :   memcpy (newehdr->e_ident, ehdr->e_ident, EI_NIDENT);
    2259          82 :   newehdr->e_type = ehdr->e_type;
    2260          82 :   newehdr->e_machine = ehdr->e_machine;
    2261          82 :   newehdr->e_version = ehdr->e_version;
    2262          82 :   newehdr->e_entry = ehdr->e_entry;
    2263          82 :   newehdr->e_flags = ehdr->e_flags;
    2264          82 :   newehdr->e_phoff = ehdr->e_phoff;
    2265             : 
    2266             :   /* We need to position the section header table.  */
    2267          82 :   const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT);
    2268         164 :   newehdr->e_shoff = ((shdr_info[shdridx].shdr.sh_offset
    2269          82 :                        + shdr_info[shdridx].shdr.sh_size + offsize - 1)
    2270          82 :                       & ~((GElf_Off) (offsize - 1)));
    2271          82 :   newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT);
    2272             : 
    2273             :   /* The new section header string table index.  */
    2274          82 :   if (likely (idx < SHN_HIRESERVE) && likely (idx != SHN_XINDEX))
    2275          82 :     newehdr->e_shstrndx = idx;
    2276             :   else
    2277             :     {
    2278             :       /* The index does not fit in the ELF header field.  */
    2279           0 :       shdr_info[0].scn = elf_getscn (elf, 0);
    2280             : 
    2281           0 :       if (gelf_getshdr (shdr_info[0].scn, &shdr_info[0].shdr) == NULL)
    2282           0 :         INTERNAL_ERROR (fname);
    2283             : 
    2284           0 :       shdr_info[0].shdr.sh_link = idx;
    2285           0 :       (void) gelf_update_shdr (shdr_info[0].scn, &shdr_info[0].shdr);
    2286             : 
    2287           0 :       newehdr->e_shstrndx = SHN_XINDEX;
    2288             :     }
    2289             : 
    2290          82 :   if (gelf_update_ehdr (newelf, newehdr) == 0)
    2291             :     {
    2292           0 :       error (0, 0, gettext ("%s: error while creating ELF header: %s"),
    2293           0 :              output_fname ?: fname, elf_errmsg (-1));
    2294           0 :       cleanup_debug ();
    2295           0 :       return 1;
    2296             :     }
    2297             : 
    2298             :   /* We have everything from the old file.  */
    2299          82 :   if (elf_cntl (elf, ELF_C_FDDONE) != 0)
    2300             :     {
    2301           0 :       error (0, 0, gettext ("%s: error while reading the file: %s"),
    2302             :              fname, elf_errmsg (-1));
    2303           0 :       cleanup_debug ();
    2304           0 :       return 1;
    2305             :     }
    2306             : 
    2307             :   /* The ELF library better follows our layout when this is not a
    2308             :      relocatable object file.  */
    2309          82 :   elf_flagelf (newelf, ELF_C_SET,
    2310          82 :                (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0)
    2311          82 :                | (permissive ? ELF_F_PERMISSIVE : 0));
    2312             : 
    2313             :   /* Finally write the file.  */
    2314          82 :   if (elf_update (newelf, ELF_C_WRITE) == -1)
    2315             :     {
    2316           0 :       error (0, 0, gettext ("while writing '%s': %s"),
    2317           0 :              output_fname ?: fname, elf_errmsg (-1));
    2318           0 :       result = 1;
    2319             :     }
    2320             : 
    2321          82 :   if (remove_shdrs)
    2322             :     {
    2323             :       /* libelf can't cope without the section headers being properly intact.
    2324             :          So we just let it write them normally, and then we nuke them later.  */
    2325             : 
    2326           0 :       if (newehdr->e_ident[EI_CLASS] == ELFCLASS32)
    2327             :         {
    2328             :           assert (offsetof (Elf32_Ehdr, e_shentsize) + sizeof (Elf32_Half)
    2329             :                   == offsetof (Elf32_Ehdr, e_shnum));
    2330             :           assert (offsetof (Elf32_Ehdr, e_shnum) + sizeof (Elf32_Half)
    2331             :                   == offsetof (Elf32_Ehdr, e_shstrndx));
    2332           0 :           const Elf32_Off zero_off = 0;
    2333           0 :           const Elf32_Half zero[3] = { 0, 0, SHN_UNDEF };
    2334           0 :           if (pwrite_retry (fd, &zero_off, sizeof zero_off,
    2335             :                             offsetof (Elf32_Ehdr, e_shoff)) != sizeof zero_off
    2336           0 :               || (pwrite_retry (fd, zero, sizeof zero,
    2337             :                                 offsetof (Elf32_Ehdr, e_shentsize))
    2338             :                   != sizeof zero)
    2339           0 :               || ftruncate (fd, shdr_info[shdridx].shdr.sh_offset) < 0)
    2340             :             {
    2341           0 :               error (0, errno, gettext ("while writing '%s'"),
    2342           0 :                      output_fname ?: fname);
    2343           0 :               result = 1;
    2344             :             }
    2345             :         }
    2346             :       else
    2347             :         {
    2348             :           assert (offsetof (Elf64_Ehdr, e_shentsize) + sizeof (Elf64_Half)
    2349             :                   == offsetof (Elf64_Ehdr, e_shnum));
    2350             :           assert (offsetof (Elf64_Ehdr, e_shnum) + sizeof (Elf64_Half)
    2351             :                   == offsetof (Elf64_Ehdr, e_shstrndx));
    2352           0 :           const Elf64_Off zero_off = 0;
    2353           0 :           const Elf64_Half zero[3] = { 0, 0, SHN_UNDEF };
    2354           0 :           if (pwrite_retry (fd, &zero_off, sizeof zero_off,
    2355             :                             offsetof (Elf64_Ehdr, e_shoff)) != sizeof zero_off
    2356           0 :               || (pwrite_retry (fd, zero, sizeof zero,
    2357             :                                 offsetof (Elf64_Ehdr, e_shentsize))
    2358             :                   != sizeof zero)
    2359           0 :               || ftruncate (fd, shdr_info[shdridx].shdr.sh_offset) < 0)
    2360             :             {
    2361           0 :               error (0, errno, gettext ("while writing '%s'"),
    2362           0 :                      output_fname ?: fname);
    2363           0 :               result = 1;
    2364             :             }
    2365             :         }
    2366             :     }
    2367             : 
    2368         169 :  fail_close:
    2369          85 :   if (shdr_info != NULL)
    2370             :     {
    2371             :       /* For some sections we might have created an table to map symbol
    2372             :          table indices.  Or we might kept (original) data around to put
    2373             :          into the .debug file.  */
    2374      199522 :       for (cnt = 1; cnt <= shdridx; ++cnt)
    2375             :         {
    2376      199437 :           free (shdr_info[cnt].newsymidx);
    2377      199437 :           if (shdr_info[cnt].debug_data != NULL)
    2378          62 :             free (shdr_info[cnt].debug_data->d_buf);
    2379             :         }
    2380             : 
    2381             :       /* Free data we allocated for the .gnu_debuglink section. */
    2382          85 :       free (debuglink_buf);
    2383             : 
    2384             :       /* Free the memory.  */
    2385          85 :       if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
    2386           3 :         free (shdr_info);
    2387             :     }
    2388             : 
    2389             :   /* Free other resources.  */
    2390          85 :   if (shstrtab_data != NULL)
    2391          83 :     free (shstrtab_data->d_buf);
    2392          85 :   if (shst != NULL)
    2393          85 :     dwelf_strtab_free (shst);
    2394             : 
    2395             :   /* That was it.  Close the descriptors.  */
    2396          85 :   if (elf_end (newelf) != 0)
    2397             :     {
    2398           0 :       error (0, 0, gettext ("error while finishing '%s': %s"),
    2399           0 :              output_fname ?: fname, elf_errmsg (-1));
    2400           0 :       result = 1;
    2401             :     }
    2402             : 
    2403         134 :   if (debugelf != NULL && elf_end (debugelf) != 0)
    2404             :     {
    2405           0 :       error (0, 0, gettext ("error while finishing '%s': %s"), debug_fname,
    2406             :              elf_errmsg (-1));
    2407           0 :       result = 1;
    2408             :     }
    2409             : 
    2410         170 :  fail:
    2411             :   /* Close the EBL backend.  */
    2412          85 :   if (ebl != NULL)
    2413          36 :     ebl_closebackend (ebl);
    2414             : 
    2415          85 :   cleanup_debug ();
    2416             : 
    2417             :   /* If requested, preserve the timestamp.  */
    2418          85 :   if (tvp != NULL)
    2419             :     {
    2420           0 :       if (futimens (fd, tvp) != 0)
    2421             :         {
    2422           0 :           error (0, errno, gettext ("\
    2423             : cannot set access and modification date of '%s'"),
    2424           0 :                  output_fname ?: fname);
    2425           0 :           result = 1;
    2426             :         }
    2427             :     }
    2428             : 
    2429             :   /* Close the file descriptor if we created a new file.  */
    2430          85 :   if (output_fname != NULL)
    2431             :     {
    2432          69 :       close (fd);
    2433          69 :       if (result != 0)
    2434           0 :        unlink (output_fname);
    2435             :     }
    2436             : 
    2437             :   return result;
    2438             : }
    2439             : 
    2440             : static void
    2441          85 : cleanup_debug (void)
    2442             : {
    2443          85 :   if (debug_fd >= 0)
    2444             :     {
    2445          49 :       if (tmp_debug_fname != NULL)
    2446             :         {
    2447           3 :           unlink (tmp_debug_fname);
    2448           3 :           free (tmp_debug_fname);
    2449           3 :           tmp_debug_fname = NULL;
    2450             :         }
    2451          49 :       close (debug_fd);
    2452          49 :       debug_fd = -1;
    2453             :     }
    2454          85 : }
    2455             : 
    2456             : static int
    2457             : handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
    2458             :            struct timespec tvp[2])
    2459             : {
    2460             :   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
    2461             :   size_t fname_len = strlen (fname) + 1;
    2462             :   char new_prefix[prefix_len + 1 + fname_len];
    2463             :   char *cp = new_prefix;
    2464             : 
    2465             :   /* Create the full name of the file.  */
    2466             :   if (prefix != NULL)
    2467             :     {
    2468             :       cp = mempcpy (cp, prefix, prefix_len);
    2469             :       *cp++ = ':';
    2470             :     }
    2471             :   memcpy (cp, fname, fname_len);
    2472             : 
    2473             : 
    2474             :   /* Process all the files contained in the archive.  */
    2475             :   Elf *subelf;
    2476             :   Elf_Cmd cmd = ELF_C_RDWR;
    2477             :   int result = 0;
    2478             :   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
    2479             :     {
    2480             :       /* The the header for this element.  */
    2481             :       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
    2482             : 
    2483             :       if (elf_kind (subelf) == ELF_K_ELF)
    2484             :         result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, 0, NULL);
    2485             :       else if (elf_kind (subelf) == ELF_K_AR)
    2486             :         result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, NULL);
    2487             : 
    2488             :       /* Get next archive element.  */
    2489             :       cmd = elf_next (subelf);
    2490             :       if (unlikely (elf_end (subelf) != 0))
    2491             :         INTERNAL_ERROR (fname);
    2492             :     }
    2493             : 
    2494             :   if (tvp != NULL)
    2495             :     {
    2496             :       if (unlikely (futimens (fd, tvp) != 0))
    2497             :         {
    2498             :           error (0, errno, gettext ("\
    2499             : cannot set access and modification date of '%s'"), fname);
    2500             :           result = 1;
    2501             :         }
    2502             :     }
    2503             : 
    2504             :   if (unlikely (close (fd) != 0))
    2505             :     error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
    2506             : 
    2507             :   return result;
    2508             : }
    2509             : 
    2510             : 
    2511             : #include "debugpred.h"

Generated by: LCOV version 1.13