LCOV - code coverage report
Current view: top level - src - unstrip.c (source / functions) Hit Total Coverage
Test: elfutils-0.175 Lines: 731 1092 66.9 %
Date: 2018-11-16 13:02:39 Functions: 32 38 84.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Combine stripped files with separate symbols and debug information.
       2             :    Copyright (C) 2007-2012, 2014, 2015 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             :    Written by Roland McGrath <roland@redhat.com>, 2007.
       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             : /* TODO:
      20             : 
      21             :   * SHX_XINDEX
      22             : 
      23             :   * prelink vs .debug_* linked addresses
      24             : 
      25             :  */
      26             : 
      27             : #ifdef HAVE_CONFIG_H
      28             : # include <config.h>
      29             : #endif
      30             : 
      31             : #include <argp.h>
      32             : #include <assert.h>
      33             : #include <errno.h>
      34             : #include <fcntl.h>
      35             : #include <fnmatch.h>
      36             : #include <libintl.h>
      37             : #include <locale.h>
      38             : #include <stdbool.h>
      39             : #include <stdio.h>
      40             : #include <stdio_ext.h>
      41             : #include <inttypes.h>
      42             : #include <stdlib.h>
      43             : #include <string.h>
      44             : #include <unistd.h>
      45             : #include <sys/stat.h>
      46             : 
      47             : #include <gelf.h>
      48             : #include <libebl.h>
      49             : #include <libdwfl.h>
      50             : #include "system.h"
      51             : #include "libdwelf.h"
      52             : #include "libeu.h"
      53             : #include "printversion.h"
      54             : 
      55             : #ifndef _
      56             : # define _(str) gettext (str)
      57             : #endif
      58             : 
      59             : /* Name and version of program.  */
      60             : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
      61             : 
      62             : /* Bug report address.  */
      63             : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
      64             : 
      65             : /* Definitions of arguments for argp functions.  */
      66             : static const struct argp_option options[] =
      67             : {
      68             :   /* Group 2 will follow group 1 from dwfl_standard_argp.  */
      69             :   { "match-file-names", 'f', NULL, 0,
      70             :     N_("Match MODULE against file names, not module names"), 2 },
      71             :   { "ignore-missing", 'i', NULL, 0, N_("Silently skip unfindable files"), 0 },
      72             : 
      73             :   { NULL, 0, NULL, 0, N_("Output options:"), 0 },
      74             :   { "output", 'o', "FILE", 0, N_("Place output into FILE"), 0 },
      75             :   { "output-directory", 'd', "DIRECTORY",
      76             :     0, N_("Create multiple output files under DIRECTORY"), 0 },
      77             :   { "module-names", 'm', NULL, 0, N_("Use module rather than file names"), 0 },
      78             :   { "all", 'a', NULL, 0,
      79             :     N_("Create output for modules that have no separate debug information"),
      80             :     0 },
      81             :   { "relocate", 'R', NULL, 0,
      82             :     N_("Apply relocations to section contents in ET_REL files"), 0 },
      83             :   { "list-only", 'n', NULL, 0,
      84             :     N_("Only list module and file names, build IDs"), 0 },
      85             :  { "force", 'F', NULL, 0,
      86             :     N_("Force combining files even if some ELF headers don't seem to match"),
      87             :    0 },
      88             :   { NULL, 0, NULL, 0, NULL, 0 }
      89             : };
      90             : 
      91             : struct arg_info
      92             : {
      93             :   const char *output_file;
      94             :   const char *output_dir;
      95             :   Dwfl *dwfl;
      96             :   char **args;
      97             :   bool list;
      98             :   bool all;
      99             :   bool ignore;
     100             :   bool modnames;
     101             :   bool match_files;
     102             :   bool relocate;
     103             :   bool force;
     104             : };
     105             : 
     106             : /* Handle program arguments.  */
     107             : static error_t
     108         140 : parse_opt (int key, char *arg, struct argp_state *state)
     109             : {
     110         140 :   struct arg_info *info = state->input;
     111             : 
     112         140 :   switch (key)
     113             :     {
     114          24 :     case ARGP_KEY_INIT:
     115          24 :       state->child_inputs[0] = &info->dwfl;
     116          24 :       break;
     117             : 
     118          16 :     case 'o':
     119          16 :       if (info->output_file != NULL)
     120             :         {
     121           0 :           argp_error (state, _("-o option specified twice"));
     122           0 :           return EINVAL;
     123             :         }
     124          16 :       info->output_file = arg;
     125          16 :       break;
     126             : 
     127           0 :     case 'd':
     128           0 :       if (info->output_dir != NULL)
     129             :         {
     130           0 :           argp_error (state, _("-d option specified twice"));
     131           0 :           return EINVAL;
     132             :         }
     133           0 :       info->output_dir = arg;
     134           0 :       break;
     135             : 
     136           0 :     case 'm':
     137           0 :       info->modnames = true;
     138           0 :       break;
     139           0 :     case 'f':
     140           0 :       info->match_files = true;
     141           0 :       break;
     142           0 :     case 'a':
     143           0 :       info->all = true;
     144           0 :       break;
     145           0 :     case 'i':
     146           0 :       info->ignore = true;
     147           0 :       break;
     148           4 :     case 'n':
     149           4 :       info->list = true;
     150           4 :       break;
     151           0 :     case 'R':
     152           0 :       info->relocate = true;
     153           0 :       break;
     154           0 :     case 'F':
     155           0 :       info->force = true;
     156           0 :       break;
     157             : 
     158          24 :     case ARGP_KEY_ARGS:
     159             :     case ARGP_KEY_NO_ARGS:
     160             :       /* We "consume" all the arguments here.  */
     161          24 :       info->args = &state->argv[state->next];
     162             : 
     163          24 :       if (info->output_file != NULL && info->output_dir != NULL)
     164             :         {
     165           0 :           argp_error (state, _("only one of -o or -d allowed"));
     166           0 :           return EINVAL;
     167             :         }
     168             : 
     169          24 :       if (info->list && (info->dwfl == NULL
     170           4 :                          || info->output_dir != NULL
     171           4 :                          || info->output_file != NULL))
     172             :         {
     173           0 :           argp_error (state,
     174           0 :                       _("-n cannot be used with explicit files or -o or -d"));
     175           0 :           return EINVAL;
     176             :         }
     177             : 
     178          24 :       if (info->output_dir != NULL)
     179             :         {
     180             :           struct stat st;
     181           0 :           error_t fail = 0;
     182           0 :           if (stat (info->output_dir, &st) < 0)
     183           0 :             fail = errno;
     184           0 :           else if (!S_ISDIR (st.st_mode))
     185             :             fail = ENOTDIR;
     186           0 :           if (fail)
     187             :             {
     188           0 :               argp_failure (state, EXIT_FAILURE, fail,
     189           0 :                             _("output directory '%s'"), info->output_dir);
     190           0 :               return fail;
     191             :             }
     192             :         }
     193             : 
     194          24 :       if (info->dwfl == NULL)
     195             :         {
     196          20 :           if (state->next + 2 != state->argc)
     197             :             {
     198           0 :               argp_error (state, _("exactly two file arguments are required"));
     199           0 :               return EINVAL;
     200             :             }
     201             : 
     202          20 :           if (info->ignore || info->all || info->modnames || info->relocate)
     203             :             {
     204           0 :               argp_error (state, _("\
     205             : -m, -a, -R, and -i options not allowed with explicit files"));
     206           0 :               return EINVAL;
     207             :             }
     208             : 
     209             :           /* Bail out immediately to prevent dwfl_standard_argp's parser
     210             :              from defaulting to "-e a.out".  */
     211             :           return ENOSYS;
     212             :         }
     213           4 :       else if (info->output_file == NULL && info->output_dir == NULL
     214           4 :                && !info->list)
     215             :         {
     216           0 :           argp_error (state,
     217           0 :                       _("-o or -d is required when using implicit files"));
     218           0 :           return EINVAL;
     219             :         }
     220             :       break;
     221             : 
     222             :     default:
     223             :       return ARGP_ERR_UNKNOWN;
     224             :     }
     225             :   return 0;
     226             : }
     227             : 
     228             : #define ELF_CHECK(call, msg)                                                  \
     229             :   do                                                                          \
     230             :     {                                                                         \
     231             :       if (unlikely (!(call)))                                                 \
     232             :         error (EXIT_FAILURE, 0, msg, elf_errmsg (-1));                        \
     233             :     } while (0)
     234             : 
     235             : /* Copy INELF to newly-created OUTELF, exit via error for any problems.  */
     236             : static void
     237          16 : copy_elf (Elf *outelf, Elf *inelf)
     238             : {
     239          16 :   ELF_CHECK (gelf_newehdr (outelf, gelf_getclass (inelf)),
     240             :              _("cannot create ELF header: %s"));
     241             : 
     242             :   size_t shstrndx;
     243          16 :   ELF_CHECK (elf_getshdrstrndx (inelf, &shstrndx) == 0,
     244             :              _("cannot get shdrstrndx:%s"));
     245             : 
     246             :   GElf_Ehdr ehdr_mem;
     247          16 :   GElf_Ehdr *ehdr = gelf_getehdr (inelf, &ehdr_mem);
     248          16 :   ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
     249          16 :   if (shstrndx < SHN_LORESERVE)
     250          15 :     ehdr->e_shstrndx = shstrndx;
     251             :   else
     252             :     {
     253           1 :       ehdr->e_shstrndx = SHN_XINDEX;
     254           1 :       Elf_Scn *scn0 = elf_getscn (outelf, 0);
     255             :       GElf_Shdr shdr0_mem;
     256           1 :       GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem);
     257           1 :       ELF_CHECK (shdr0 != NULL,
     258             :                  _("cannot get new zero section: %s"));
     259           1 :       shdr0->sh_link = shstrndx;
     260           1 :       ELF_CHECK (gelf_update_shdr (scn0, shdr0),
     261             :                  _("cannot update new zero section: %s"));
     262             :     }
     263             : 
     264          16 :   ELF_CHECK (gelf_update_ehdr (outelf, ehdr),
     265             :              _("cannot copy ELF header: %s"));
     266             : 
     267             :   size_t phnum;
     268          16 :   ELF_CHECK (elf_getphdrnum (inelf, &phnum) == 0,
     269             :              _("cannot get number of program headers: %s"));
     270             : 
     271          16 :   if (phnum > 0)
     272             :     {
     273           9 :       ELF_CHECK (gelf_newphdr (outelf, phnum),
     274             :                  _("cannot create program headers: %s"));
     275             : 
     276             :       GElf_Phdr phdr_mem;
     277          63 :       for (size_t i = 0; i < phnum; ++i)
     278          63 :         ELF_CHECK (gelf_update_phdr (outelf, i,
     279             :                                      gelf_getphdr (inelf, i, &phdr_mem)),
     280             :                    _("cannot copy program header: %s"));
     281             :     }
     282             : 
     283             :   Elf_Scn *scn = NULL;
     284       66075 :   while ((scn = elf_nextscn (inelf, scn)) != NULL)
     285             :     {
     286       66059 :       Elf_Scn *newscn = elf_newscn (outelf);
     287             : 
     288             :       GElf_Shdr shdr_mem;
     289       66059 :       ELF_CHECK (gelf_update_shdr (newscn, gelf_getshdr (scn, &shdr_mem)),
     290             :                  _("cannot copy section header: %s"));
     291             : 
     292       66059 :       Elf_Data *data = elf_getdata (scn, NULL);
     293       66059 :       ELF_CHECK (data != NULL, _("cannot get section data: %s"));
     294       66059 :       Elf_Data *newdata = elf_newdata (newscn);
     295       66059 :       ELF_CHECK (newdata != NULL, _("cannot copy section data: %s"));
     296       66059 :       *newdata = *data;
     297       66059 :       elf_flagdata (newdata, ELF_C_SET, ELF_F_DIRTY);
     298             :     }
     299          16 : }
     300             : 
     301             : /* Create directories containing PATH.  */
     302             : static void
     303           0 : make_directories (const char *path)
     304             : {
     305           0 :   const char *lastslash = strrchr (path, '/');
     306           0 :   if (lastslash == NULL)
     307             :     return;
     308             : 
     309           0 :   while (lastslash > path && lastslash[-1] == '/')
     310           0 :     --lastslash;
     311           0 :   if (lastslash == path)
     312             :     return;
     313             : 
     314           0 :   char *dir = strndupa (path, lastslash - path);
     315           0 :   while (mkdir (dir, 0777) < 0 && errno != EEXIST)
     316           0 :     if (errno == ENOENT)
     317           0 :       make_directories (dir);
     318             :     else
     319           0 :       error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir);
     320             : }
     321             : 
     322             : /* Keep track of new section data we are creating, so we can free it
     323             :    when done.  */
     324             : struct data_list
     325             : {
     326             :   void *data;
     327             :   struct data_list *next;
     328             : };
     329             : 
     330             : struct data_list *new_data_list;
     331             : 
     332             : static void
     333             : record_new_data (void *data)
     334             : {
     335          19 :   struct data_list *next = new_data_list;
     336          19 :   new_data_list = xmalloc (sizeof (struct data_list));
     337          19 :   new_data_list->data = data;
     338          19 :   new_data_list->next = next;
     339             : }
     340             : 
     341             : static void
     342          20 : free_new_data (void)
     343             : {
     344          20 :   struct data_list *list = new_data_list;
     345          59 :   while (list != NULL)
     346             :     {
     347          19 :       struct data_list *next = list->next;
     348          19 :       free (list->data);
     349          19 :       free (list);
     350          19 :       list = next;
     351             :     }
     352          20 :   new_data_list = NULL;
     353          20 : }
     354             : 
     355             : /* The binutils linker leaves gratuitous section symbols in .symtab
     356             :    that strip has to remove.  Older linkers likewise include a
     357             :    symbol for every section, even unallocated ones, in .dynsym.
     358             :    Because of this, the related sections can shrink in the stripped
     359             :    file from their original size.  Older versions of strip do not
     360             :    adjust the sh_size field in the debuginfo file's SHT_NOBITS
     361             :    version of the section header, so it can appear larger.  */
     362             : static bool
     363             : section_can_shrink (const GElf_Shdr *shdr)
     364             : {
     365           7 :   switch (shdr->sh_type)
     366             :     {
     367             :     case SHT_SYMTAB:
     368             :     case SHT_DYNSYM:
     369             :     case SHT_HASH:
     370             :     case SHT_GNU_versym:
     371             :       return true;
     372             :     }
     373             :   return false;
     374             : }
     375             : 
     376             : /* See if this symbol table has a leading section symbol for every single
     377             :    section, in order.  The binutils linker produces this.  While we're here,
     378             :    update each section symbol's st_value.  */
     379             : static size_t
     380          12 : symtab_count_leading_section_symbols (Elf *elf, Elf_Scn *scn, size_t shnum,
     381             :                                       Elf_Data *newsymdata)
     382             : {
     383          12 :   Elf_Data *data = elf_getdata (scn, NULL);
     384          12 :   Elf_Data *shndxdata = NULL;   /* XXX */
     385             : 
     386          78 :   for (size_t i = 1; i < shnum; ++i)
     387             :     {
     388             :       GElf_Sym sym_mem;
     389          78 :       GElf_Word shndx = SHN_UNDEF;
     390          78 :       GElf_Sym *sym = gelf_getsymshndx (data, shndxdata, i, &sym_mem, &shndx);
     391          78 :       ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
     392             : 
     393             :       GElf_Shdr shdr_mem;
     394          78 :       GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, i), &shdr_mem);
     395          78 :       ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
     396             : 
     397          78 :       if (sym->st_shndx != SHN_XINDEX)
     398          78 :         shndx = sym->st_shndx;
     399             : 
     400          78 :       if (shndx != i || GELF_ST_TYPE (sym->st_info) != STT_SECTION)
     401          12 :         return i;
     402             : 
     403          66 :       sym->st_value = shdr->sh_addr;
     404          66 :       if (sym->st_shndx != SHN_XINDEX)
     405          66 :         shndx = SHN_UNDEF;
     406          66 :       ELF_CHECK (gelf_update_symshndx (newsymdata, shndxdata, i, sym, shndx),
     407             :                  _("cannot update symbol table: %s"));
     408             :     }
     409             : 
     410             :   return shnum;
     411             : }
     412             : 
     413             : static void
     414       66425 : update_shdr (Elf_Scn *outscn, GElf_Shdr *newshdr)
     415             : {
     416       66425 :   ELF_CHECK (gelf_update_shdr (outscn, newshdr),
     417             :              _("cannot update section header: %s"));
     418       66425 : }
     419             : 
     420             : /* We expanded the output section, so update its header.  */
     421             : static void
     422           6 : update_sh_size (Elf_Scn *outscn, const Elf_Data *data)
     423             : {
     424             :   GElf_Shdr shdr_mem;
     425           6 :   GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
     426           6 :   ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
     427             : 
     428           6 :   newshdr->sh_size = data->d_size;
     429             : 
     430           6 :   update_shdr (outscn, newshdr);
     431           6 : }
     432             : 
     433             : /* Update relocation sections using the symbol table.  */
     434             : static void
     435         135 : adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr,
     436             :                size_t map[], const GElf_Shdr *symshdr)
     437             : {
     438         135 :   Elf_Data *data = elf_getdata (outscn, NULL);
     439             : 
     440             :   inline void adjust_reloc (GElf_Xword *info)
     441             :     {
     442       27964 :       size_t ndx = GELF_R_SYM (*info);
     443       27964 :       if (ndx != STN_UNDEF)
     444       27958 :         *info = GELF_R_INFO (map[ndx - 1], GELF_R_TYPE (*info));
     445             :     }
     446             : 
     447         135 :   switch (shdr->sh_type)
     448             :     {
     449          23 :     case SHT_REL:
     450          23 :       if (shdr->sh_entsize == 0)
     451             :         error (EXIT_FAILURE, 0, "REL section cannot have zero sh_entsize");
     452             : 
     453        2258 :       for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
     454             :         {
     455             :           GElf_Rel rel_mem;
     456        2258 :           GElf_Rel *rel = gelf_getrel (data, i, &rel_mem);
     457        4516 :           adjust_reloc (&rel->r_info);
     458        2258 :           ELF_CHECK (gelf_update_rel (data, i, rel),
     459             :                      _("cannot update relocation: %s"));
     460             :         }
     461             :       break;
     462             : 
     463          99 :     case SHT_RELA:
     464          99 :       if (shdr->sh_entsize == 0)
     465             :         error (EXIT_FAILURE, 0, "RELA section cannot have zero sh_entsize");
     466             : 
     467       25706 :       for (size_t i = 0; i < shdr->sh_size / shdr->sh_entsize; ++i)
     468             :         {
     469             :           GElf_Rela rela_mem;
     470       25706 :           GElf_Rela *rela = gelf_getrela (data, i, &rela_mem);
     471       51412 :           adjust_reloc (&rela->r_info);
     472       25706 :           ELF_CHECK (gelf_update_rela (data, i, rela),
     473             :                      _("cannot update relocation: %s"));
     474             :         }
     475             :       break;
     476             : 
     477           7 :     case SHT_GROUP:
     478             :       {
     479             :         GElf_Shdr shdr_mem;
     480           7 :         GElf_Shdr *newshdr = gelf_getshdr (outscn, &shdr_mem);
     481           7 :         ELF_CHECK (newshdr != NULL, _("cannot get section header: %s"));
     482           7 :         if (newshdr->sh_info != STN_UNDEF)
     483             :           {
     484           7 :             newshdr->sh_info = map[newshdr->sh_info - 1];
     485           7 :             update_shdr (outscn, newshdr);
     486             :           }
     487             :         break;
     488             :       }
     489             : 
     490           3 :     case SHT_HASH:
     491             :       /* We must expand the table and rejigger its contents.  */
     492             :       {
     493           3 :         if (shdr->sh_entsize == 0)
     494             :           error (EXIT_FAILURE, 0, "HASH section cannot have zero sh_entsize");
     495           3 :         if (symshdr->sh_entsize == 0)
     496             :           error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
     497           3 :         const size_t nsym = symshdr->sh_size / symshdr->sh_entsize;
     498           3 :         const size_t onent = shdr->sh_size / shdr->sh_entsize;
     499           3 :         assert (data->d_size == shdr->sh_size);
     500             : 
     501             : #define CONVERT_HASH(Hash_Word)                                               \
     502             :         {                                                                     \
     503             :           const Hash_Word *const old_hash = data->d_buf;                   \
     504             :           const size_t nbucket = old_hash[0];                                 \
     505             :           const size_t nchain = old_hash[1];                                  \
     506             :           const Hash_Word *const old_bucket = &old_hash[2];               \
     507             :           const Hash_Word *const old_chain = &old_bucket[nbucket];        \
     508             :           assert (onent == 2 + nbucket + nchain);                             \
     509             :                                                                               \
     510             :           const size_t nent = 2 + nbucket + nsym;                             \
     511             :           Hash_Word *const new_hash = xcalloc (nent, sizeof new_hash[0]);     \
     512             :           Hash_Word *const new_bucket = &new_hash[2];                             \
     513             :           Hash_Word *const new_chain = &new_bucket[nbucket];                      \
     514             :                                                                               \
     515             :           new_hash[0] = nbucket;                                              \
     516             :           new_hash[1] = nsym;                                                 \
     517             :           for (size_t i = 0; i < nbucket; ++i)                                     \
     518             :             if (old_bucket[i] != STN_UNDEF)                                   \
     519             :               new_bucket[i] = map[old_bucket[i] - 1];                         \
     520             :                                                                               \
     521             :           for (size_t i = 1; i < nchain; ++i)                                      \
     522             :             if (old_chain[i] != STN_UNDEF)                                    \
     523             :               new_chain[map[i - 1]] = map[old_chain[i] - 1];                  \
     524             :                                                                               \
     525             :           record_new_data (new_hash);                                   \
     526             :           data->d_buf = new_hash;                                          \
     527             :           data->d_size = nent * sizeof new_hash[0];                        \
     528             :         }
     529             : 
     530           3 :         switch (shdr->sh_entsize)
     531             :           {
     532           3 :           case 4:
     533           6 :             CONVERT_HASH (Elf32_Word);
     534             :             break;
     535           0 :           case 8:
     536           0 :             CONVERT_HASH (Elf64_Xword);
     537             :             break;
     538           0 :           default:
     539           0 :             abort ();
     540             :           }
     541             : 
     542           3 :         elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
     543           3 :         update_sh_size (outscn, data);
     544             : 
     545             : #undef  CONVERT_HASH
     546             :       }
     547             :       break;
     548             : 
     549           3 :     case SHT_GNU_versym:
     550             :       /* We must expand the table and move its elements around.  */
     551             :       {
     552           3 :         if (shdr->sh_entsize == 0)
     553             :           error (EXIT_FAILURE, 0,
     554             :                  "GNU_versym section cannot have zero sh_entsize");
     555           3 :         if (symshdr->sh_entsize == 0)
     556             :           error (EXIT_FAILURE, 0, "Symbol table cannot have zero sh_entsize");
     557           3 :         const size_t nent = symshdr->sh_size / symshdr->sh_entsize;
     558           3 :         const size_t onent = shdr->sh_size / shdr->sh_entsize;
     559           3 :         assert (nent >= onent);
     560             : 
     561             :         /* We don't bother using gelf_update_versym because there is
     562             :            really no conversion to be done.  */
     563             :         assert (sizeof (Elf32_Versym) == sizeof (GElf_Versym));
     564             :         assert (sizeof (Elf64_Versym) == sizeof (GElf_Versym));
     565           3 :         GElf_Versym *versym = xcalloc (nent, sizeof versym[0]);
     566             : 
     567         105 :         for (size_t i = 1; i < onent; ++i)
     568             :           {
     569         102 :             GElf_Versym *v = gelf_getversym (data, i, &versym[map[i - 1]]);
     570         102 :             ELF_CHECK (v != NULL, _("cannot get symbol version: %s"));
     571             :           }
     572             : 
     573           3 :         record_new_data (versym);
     574           3 :         data->d_buf = versym;
     575           3 :         data->d_size = nent * shdr->sh_entsize;
     576           3 :         elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY);
     577           3 :         update_sh_size (outscn, data);
     578             :       }
     579             :       break;
     580             : 
     581           0 :     default:
     582           0 :       error (EXIT_FAILURE, 0,
     583           0 :              _("unexpected section type in [%zu] with sh_link to symtab"),
     584             :              elf_ndxscn (inscn));
     585             :     }
     586         135 : }
     587             : 
     588             : /* Adjust all the relocation sections in the file.  */
     589             : static void
     590          13 : adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
     591             :                    size_t map[])
     592             : {
     593          13 :   size_t new_sh_link = elf_ndxscn (symtab);
     594          13 :   Elf_Scn *scn = NULL;
     595         452 :   while ((scn = elf_nextscn (elf, scn)) != NULL)
     596         426 :     if (scn != symtab)
     597             :       {
     598             :         GElf_Shdr shdr_mem;
     599         413 :         GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
     600         413 :         ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
     601             :         /* Don't redo SHT_GROUP, groups are in both the stripped and debug,
     602             :            it will already have been done by adjust_relocs for the
     603             :            stripped_symtab.  */
     604         413 :         if (shdr->sh_type != SHT_NOBITS && shdr->sh_type != SHT_GROUP
     605         393 :             && shdr->sh_link == new_sh_link)
     606          87 :           adjust_relocs (scn, scn, shdr, map, symshdr);
     607             :       }
     608          13 : }
     609             : 
     610             : /* The original file probably had section symbols for all of its
     611             :    sections, even the unallocated ones.  To match it as closely as
     612             :    possible, add in section symbols for the added sections.  */
     613             : static Elf_Data *
     614           3 : add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
     615             :                          Elf *elf, bool rel, Elf_Scn *symscn, size_t shnum)
     616           3 : {
     617           3 :   const size_t added = shnum - old_shnum;
     618             : 
     619             :   GElf_Shdr shdr_mem;
     620           3 :   GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem);
     621           3 :   ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
     622           3 :   if (shdr->sh_entsize == 0)
     623             :     error (EXIT_FAILURE, 0, "Symbol table section cannot have zero sh_entsize");
     624             : 
     625           3 :   const size_t nsym = shdr->sh_size / shdr->sh_entsize;
     626           3 :   size_t symndx_map[nsym - 1];
     627             : 
     628           3 :   shdr->sh_info += added;
     629           3 :   shdr->sh_size += added * shdr->sh_entsize;
     630           3 :   update_shdr (symscn, shdr);
     631             : 
     632           3 :   Elf_Data *symdata = elf_getdata (symscn, NULL);
     633           3 :   Elf_Data *shndxdata = NULL;   /* XXX */
     634             : 
     635           3 :   symdata->d_size = shdr->sh_size;
     636           3 :   symdata->d_buf = xmalloc (symdata->d_size);
     637           6 :   record_new_data (symdata->d_buf);
     638             : 
     639             :   /* Copy the existing section symbols.  */
     640           3 :   Elf_Data *old_symdata = elf_getdata (old_symscn, NULL);
     641          72 :   for (size_t i = 0; i < old_shnum; ++i)
     642             :     {
     643             :       GElf_Sym sym_mem;
     644          69 :       GElf_Word shndx = SHN_UNDEF;
     645          69 :       GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
     646             :                                         i, &sym_mem, &shndx);
     647          69 :       ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
     648             :                                        sym, shndx),
     649             :                  _("cannot update symbol table: %s"));
     650             : 
     651          69 :       if (i > 0)
     652          66 :         symndx_map[i - 1] = i;
     653             :     }
     654             : 
     655             :   /* Add in the new section symbols.  */
     656          24 :   for (size_t i = old_shnum; i < shnum; ++i)
     657             :     {
     658             :       GElf_Shdr i_shdr_mem;
     659          24 :       GElf_Shdr *i_shdr = gelf_getshdr (elf_getscn (elf, i), &i_shdr_mem);
     660          24 :       ELF_CHECK (i_shdr != NULL, _("cannot get section header: %s"));
     661          48 :       GElf_Sym sym =
     662             :         {
     663          24 :           .st_value = rel ? 0 : i_shdr->sh_addr,
     664             :           .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
     665             :           .st_shndx = i < SHN_LORESERVE ? i : SHN_XINDEX
     666             :         };
     667          24 :       GElf_Word shndx = i < SHN_LORESERVE ? SHN_UNDEF : i;
     668          24 :       ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, i,
     669             :                                        &sym, shndx),
     670             :                  _("cannot update symbol table: %s"));
     671             :     }
     672             : 
     673             :   /* Now copy the rest of the existing symbols.  */
     674          36 :   for (size_t i = old_shnum; i < nsym; ++i)
     675             :     {
     676             :       GElf_Sym sym_mem;
     677          36 :       GElf_Word shndx = SHN_UNDEF;
     678          36 :       GElf_Sym *sym = gelf_getsymshndx (old_symdata, shndxdata,
     679             :                                         i, &sym_mem, &shndx);
     680          36 :       ELF_CHECK (gelf_update_symshndx (symdata, shndxdata,
     681             :                                        i + added, sym, shndx),
     682             :                  _("cannot update symbol table: %s"));
     683             : 
     684          36 :       symndx_map[i - 1] = i + added;
     685             :     }
     686             : 
     687             :   /* Adjust any relocations referring to the old symbol table.  */
     688           3 :   adjust_all_relocs (elf, symscn, shdr, symndx_map);
     689             : 
     690           3 :   return symdata;
     691             : }
     692             : 
     693             : /* This has the side effect of updating STT_SECTION symbols' values,
     694             :    in case of prelink adjustments.  */
     695             : static Elf_Data *
     696          12 : check_symtab_section_symbols (Elf *elf, bool rel, Elf_Scn *scn,
     697             :                               size_t shnum, size_t shstrndx,
     698             :                               Elf_Scn *oscn, size_t oshnum, size_t oshstrndx,
     699             :                               size_t debuglink)
     700             : {
     701          12 :   size_t n = symtab_count_leading_section_symbols (elf, oscn, oshnum,
     702             :                                                    elf_getdata (scn, NULL));
     703             : 
     704          12 :   if (n == oshnum)
     705           0 :     return add_new_section_symbols (oscn, n, elf, rel, scn, shnum);
     706             : 
     707          12 :   if (n == oshstrndx || (n == debuglink && n == oshstrndx - 1))
     708           3 :     return add_new_section_symbols (oscn, n, elf, rel, scn, shstrndx);
     709             : 
     710             :   return NULL;
     711             : }
     712             : 
     713             : struct section
     714             : {
     715             :   Elf_Scn *scn;
     716             :   const char *name;
     717             :   const char *sig;
     718             :   Elf_Scn *outscn;
     719             :   Dwelf_Strent *strent;
     720             :   GElf_Shdr shdr;
     721             : };
     722             : 
     723             : static int
     724         775 : compare_alloc_sections (const struct section *s1, const struct section *s2,
     725             :                         bool rel)
     726             : {
     727         775 :   if (!rel)
     728             :     {
     729             :       /* Sort by address.  */
     730         632 :       if (s1->shdr.sh_addr < s2->shdr.sh_addr)
     731             :         return -1;
     732           2 :       if (s1->shdr.sh_addr > s2->shdr.sh_addr)
     733             :         return 1;
     734             :     }
     735             : 
     736             :   /* At the same address, preserve original section order.  */
     737         145 :   return (ssize_t) elf_ndxscn (s1->scn) - (ssize_t) elf_ndxscn (s2->scn);
     738             : }
     739             : 
     740             : static int
     741      197686 : compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
     742             :                           const char *name1, const char *name2,
     743             :                           const char *sig1, const char *sig2)
     744             : {
     745             :   /* Sort by sh_flags as an arbitrary ordering.  */
     746      197686 :   if (shdr1->sh_flags < shdr2->sh_flags)
     747             :     return -1;
     748      197581 :   if (shdr1->sh_flags > shdr2->sh_flags)
     749             :     return 1;
     750             : 
     751             :   /* Sizes should be the same.  */
     752      197403 :   if (shdr1->sh_size < shdr2->sh_size)
     753             :     return -1;
     754         489 :   if (shdr1->sh_size > shdr2->sh_size)
     755             :     return 1;
     756             : 
     757             :   /* Are they both SHT_GROUP sections? Then compare signatures.  */
     758         114 :   if (sig1 != NULL && sig2 != NULL)
     759          11 :     return strcmp (sig1, sig2);
     760             : 
     761             :   /* Sort by name as last resort.  */
     762         103 :   return strcmp (name1, name2);
     763             : }
     764             : 
     765             : static int
     766        1277 : compare_sections (const void *a, const void *b, bool rel)
     767             : {
     768        1277 :   const struct section *s1 = a;
     769        1277 :   const struct section *s2 = b;
     770             : 
     771             :   /* Sort all non-allocated sections last.  */
     772        1277 :   if ((s1->shdr.sh_flags ^ s2->shdr.sh_flags) & SHF_ALLOC)
     773         201 :     return (s1->shdr.sh_flags & SHF_ALLOC) ? -1 : 1;
     774             : 
     775        1076 :   return ((s1->shdr.sh_flags & SHF_ALLOC)
     776         775 :           ? compare_alloc_sections (s1, s2, rel)
     777        1851 :           : compare_unalloc_sections (&s1->shdr, &s2->shdr,
     778             :                                       s1->name, s2->name,
     779             :                                       s1->sig, s2->sig));
     780             : }
     781             : 
     782             : static int
     783         566 : compare_sections_rel (const void *a, const void *b)
     784             : {
     785         566 :   return compare_sections (a, b, true);
     786             : }
     787             : 
     788             : static int
     789         711 : compare_sections_nonrel (const void *a, const void *b)
     790             : {
     791         711 :   return compare_sections (a, b, false);
     792             : }
     793             : 
     794             : 
     795             : struct symbol
     796             : {
     797             :   size_t *map;
     798             : 
     799             :   union
     800             :   {
     801             :     const char *name;
     802             :     Dwelf_Strent *strent;
     803             :   };
     804             :   union
     805             :   {
     806             :     struct
     807             :     {
     808             :       GElf_Addr value;
     809             :       GElf_Xword size;
     810             :       GElf_Word shndx;
     811             :       union
     812             :       {
     813             :         struct
     814             :         {
     815             :           uint8_t info;
     816             :           uint8_t other;
     817             :         } info;
     818             :         int16_t compare;
     819             :       };
     820             :     };
     821             : 
     822             :     /* For a symbol discarded after first sort, this matches its better's
     823             :        map pointer.  */
     824             :     size_t *duplicate;
     825             :   };
     826             : };
     827             : 
     828             : /* Collect input symbols into our internal form.  */
     829             : static void
     830          20 : collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
     831             :                  const size_t nent, const GElf_Addr bias,
     832             :                  const size_t scnmap[], struct symbol *table, size_t *map,
     833             :                  struct section *split_bss)
     834             : {
     835          20 :   Elf_Data *symdata = elf_getdata (symscn, NULL);
     836          20 :   Elf_Data *strdata = elf_getdata (strscn, NULL);
     837          20 :   Elf_Data *shndxdata = NULL;   /* XXX */
     838             : 
     839        1748 :   for (size_t i = 1; i < nent; ++i)
     840             :     {
     841             :       GElf_Sym sym_mem;
     842        1728 :       GElf_Word shndx = SHN_UNDEF;
     843        1728 :       GElf_Sym *sym = gelf_getsymshndx (symdata, shndxdata, i,
     844             :                                         &sym_mem, &shndx);
     845        1728 :       ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s"));
     846        1728 :       if (sym->st_shndx != SHN_XINDEX)
     847        1728 :         shndx = sym->st_shndx;
     848             : 
     849        1728 :       if (sym->st_name >= strdata->d_size)
     850             :         error (EXIT_FAILURE, 0,
     851           0 :                _("invalid string offset in symbol [%zu]"), i);
     852             : 
     853        1728 :       struct symbol *s = &table[i - 1];
     854        1728 :       s->map = &map[i - 1];
     855        1728 :       s->name = strdata->d_buf + sym->st_name;
     856        1728 :       s->value = sym->st_value + bias;
     857        1728 :       s->size = sym->st_size;
     858        1728 :       s->shndx = shndx;
     859        1728 :       s->info.info = sym->st_info;
     860        1728 :       s->info.other = sym->st_other;
     861             : 
     862        1728 :       if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
     863         388 :         s->shndx = scnmap[shndx - 1];
     864             : 
     865        1728 :       if (GELF_ST_TYPE (s->info.info) == STT_SECTION && !rel)
     866         114 :         {
     867             :           /* Update the value to match the output section.  */
     868             :           GElf_Shdr shdr_mem;
     869         114 :           GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, s->shndx),
     870             :                                           &shdr_mem);
     871         114 :           ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
     872         114 :           s->value = shdr->sh_addr;
     873             :         }
     874        1614 :       else if (split_bss != NULL
     875           0 :                && s->value < split_bss->shdr.sh_addr
     876           0 :                && s->value >= split_bss[-1].shdr.sh_addr
     877           0 :                && shndx == elf_ndxscn (split_bss->outscn))
     878             :         /* This symbol was in .bss and was split into .dynbss.  */
     879           0 :         s->shndx = elf_ndxscn (split_bss[-1].outscn);
     880             :     }
     881          20 : }
     882             : 
     883             : 
     884             : #define CMP(value)                                                            \
     885             :   if (s1->value < s2->value)                                                 \
     886             :     return -1;                                                                \
     887             :   if (s1->value > s2->value)                                                 \
     888             :     return 1
     889             : 
     890             : /* Compare symbols with a consistent ordering,
     891             :    but one only meaningful for equality.  */
     892             : static int
     893       12118 : compare_symbols (const void *a, const void *b)
     894             : {
     895       12118 :   const struct symbol *s1 = a;
     896       12118 :   const struct symbol *s2 = b;
     897             : 
     898       12118 :   CMP (value);
     899        7359 :   CMP (size);
     900        6914 :   CMP (shndx);
     901             : 
     902        4935 :   return (s1->compare - s2->compare) ?: strcmp (s1->name, s2->name);
     903             : }
     904             : 
     905             : /* Compare symbols for output order after slots have been assigned.  */
     906             : static int
     907       11196 : compare_symbols_output (const void *a, const void *b)
     908             : {
     909       11196 :   const struct symbol *s1 = a;
     910       11196 :   const struct symbol *s2 = b;
     911             :   int cmp;
     912             : 
     913             :   /* Sort discarded symbols last.  */
     914       11196 :   cmp = (s1->name == NULL) - (s2->name == NULL);
     915             : 
     916       11196 :   if (cmp == 0)
     917             :     /* Local symbols must come first.  */
     918       18414 :     cmp = ((GELF_ST_BIND (s2->info.info) == STB_LOCAL)
     919        9207 :            - (GELF_ST_BIND (s1->info.info) == STB_LOCAL));
     920             : 
     921       11196 :   if (cmp == 0)
     922             :     /* binutils always puts section symbols first.  */
     923       15966 :     cmp = ((GELF_ST_TYPE (s2->info.info) == STT_SECTION)
     924        7983 :            - (GELF_ST_TYPE (s1->info.info) == STT_SECTION));
     925             : 
     926       11196 :   if (cmp == 0)
     927             :     {
     928        7253 :       if (GELF_ST_TYPE (s1->info.info) == STT_SECTION)
     929             :         {
     930             :           /* binutils always puts section symbols in section index order.  */
     931         944 :           CMP (shndx);
     932             :           else
     933           0 :             assert (s1 == s2);
     934             :         }
     935             : 
     936             :       /* Nothing really matters, so preserve the original order.  */
     937        6309 :       CMP (map);
     938             :       else
     939           0 :         assert (s1 == s2);
     940             :     }
     941             : 
     942             :   return cmp;
     943             : }
     944             : 
     945             : #undef CMP
     946             : 
     947             : /* Return true if the flags of the sections match, ignoring the SHF_INFO_LINK
     948             :    flag if the section contains relocation information.  */
     949             : static bool
     950             : sections_flags_match (Elf64_Xword sh_flags1, Elf64_Xword sh_flags2,
     951             :                       Elf64_Word sh_type)
     952             : {
     953         349 :   if (sh_type == SHT_REL || sh_type == SHT_RELA)
     954             :     {
     955          23 :       sh_flags1 &= ~SHF_INFO_LINK;
     956          23 :       sh_flags2 &= ~SHF_INFO_LINK;
     957             :     }
     958             : 
     959             :   return sh_flags1 == sh_flags2;
     960             : }
     961             : 
     962             : /* Return true iff the flags, size, and name match.  */
     963             : static bool
     964         349 : sections_match (const struct section *sections, size_t i,
     965             :                 const GElf_Shdr *shdr, const char *name)
     966             : {
     967         698 :   return (sections_flags_match (sections[i].shdr.sh_flags, shdr->sh_flags,
     968         349 :                                 sections[i].shdr.sh_type)
     969         347 :           && (sections[i].shdr.sh_size == shdr->sh_size
     970           7 :               || (sections[i].shdr.sh_size < shdr->sh_size
     971           7 :                   && section_can_shrink (&sections[i].shdr)))
     972         696 :           && !strcmp (sections[i].name, name));
     973             : }
     974             : 
     975             : /* Locate a matching allocated section in SECTIONS.  */
     976             : static struct section *
     977         272 : find_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name,
     978             :                     struct section sections[], size_t nalloc)
     979             : {
     980         272 :   const GElf_Addr addr = shdr->sh_addr + bias;
     981         272 :   size_t l = 0, u = nalloc;
     982        1320 :   while (l < u)
     983             :     {
     984        1048 :       size_t i = (l + u) / 2;
     985        1048 :       if (addr < sections[i].shdr.sh_addr)
     986             :         u = i;
     987         605 :       else if (addr > sections[i].shdr.sh_addr)
     988         333 :         l = i + 1;
     989             :       else
     990             :         {
     991             :           /* We've found allocated sections with this address.
     992             :              Find one with matching size, flags, and name.  */
     993         276 :           while (i > 0 && sections[i - 1].shdr.sh_addr == addr)
     994           4 :             --i;
     995         274 :           for (; i < nalloc && sections[i].shdr.sh_addr == addr;
     996           2 :                ++i)
     997         274 :             if (sections_match (sections, i, shdr, name))
     998             :               return &sections[i];
     999             :           break;
    1000             :         }
    1001             :     }
    1002             :   return NULL;
    1003             : }
    1004             : 
    1005             : static inline const char *
    1006       66184 : get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
    1007             : {
    1008       66184 :   if (shdr->sh_name >= shstrtab->d_size)
    1009           0 :     error (EXIT_FAILURE, 0, _("cannot read section [%zu] name: %s"),
    1010             :            ndx, elf_errmsg (-1));
    1011       66184 :   return shstrtab->d_buf + shdr->sh_name;
    1012             : }
    1013             : 
    1014             : /* Returns the signature of a group section, or NULL if the given
    1015             :    section isn't a group.  */
    1016             : static const char *
    1017       66286 : get_group_sig (Elf *elf, GElf_Shdr *shdr)
    1018             : {
    1019       66286 :   if (shdr->sh_type != SHT_GROUP)
    1020             :     return NULL;
    1021             : 
    1022          14 :   Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
    1023          14 :   if (symscn == NULL)
    1024           0 :     error (EXIT_FAILURE, 0, _("bad sh_link for group section: %s"),
    1025             :            elf_errmsg (-1));
    1026             : 
    1027             :   GElf_Shdr symshdr_mem;
    1028          14 :   GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
    1029          14 :   if (symshdr == NULL)
    1030           0 :     error (EXIT_FAILURE, 0, _("couldn't get shdr for group section: %s"),
    1031             :            elf_errmsg (-1));
    1032             : 
    1033          14 :   Elf_Data *symdata = elf_getdata (symscn, NULL);
    1034          14 :   if (symdata == NULL)
    1035           0 :     error (EXIT_FAILURE, 0, _("bad data for group symbol section: %s"),
    1036             :            elf_errmsg (-1));
    1037             : 
    1038             :   GElf_Sym sym_mem;
    1039          14 :   GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
    1040          14 :   if (sym == NULL)
    1041           0 :     error (EXIT_FAILURE, 0, _("couldn't get symbol for group section: %s"),
    1042             :            elf_errmsg (-1));
    1043             : 
    1044          14 :   const char *sig = elf_strptr (elf, symshdr->sh_link, sym->st_name);
    1045          14 :   if (sig == NULL)
    1046           0 :     error (EXIT_FAILURE, 0, _("bad symbol name for group section: %s"),
    1047             :            elf_errmsg (-1));
    1048             : 
    1049             :   return sig;
    1050             : }
    1051             : 
    1052             : /* Fix things up when prelink has moved some allocated sections around
    1053             :    and the debuginfo file's section headers no longer match up.
    1054             :    This fills in SECTIONS[0..NALLOC-1].outscn or exits.
    1055             :    If there was a .bss section that was split into two sections
    1056             :    with the new one preceding it in sh_addr, we return that pointer.  */
    1057             : static struct section *
    1058           0 : find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
    1059             :                              Elf *main, const GElf_Ehdr *main_ehdr,
    1060             :                              Elf_Data *main_shstrtab, GElf_Addr bias,
    1061             :                              struct section *sections,
    1062             :                              size_t nalloc, size_t nsections)
    1063             : {
    1064           0 :   Elf_Scn *undo = NULL;
    1065           0 :   for (size_t i = nalloc; i < nsections; ++i)
    1066             :     {
    1067           0 :       const struct section *sec = &sections[i];
    1068           0 :       if (sec->shdr.sh_type == SHT_PROGBITS
    1069           0 :           && !(sec->shdr.sh_flags & SHF_ALLOC)
    1070           0 :           && !strcmp (sec->name, ".gnu.prelink_undo"))
    1071             :         {
    1072           0 :           undo = sec->scn;
    1073             :           break;
    1074             :         }
    1075             :     }
    1076             : 
    1077             :   /* Find the original allocated sections before prelinking.  */
    1078           0 :   struct section *undo_sections = NULL;
    1079           0 :   size_t undo_nalloc = 0;
    1080           0 :   if (undo != NULL)
    1081             :     {
    1082             :       /* Clear assignments that might have been bogus.  */
    1083           0 :       for (size_t i = 0; i < nalloc; ++i)
    1084           0 :         sections[i].outscn = NULL;
    1085             : 
    1086           0 :       Elf_Data *undodata = elf_rawdata (undo, NULL);
    1087           0 :       ELF_CHECK (undodata != NULL,
    1088             :                  _("cannot read '.gnu.prelink_undo' section: %s"));
    1089             : 
    1090             :       union
    1091             :       {
    1092             :         Elf32_Ehdr e32;
    1093             :         Elf64_Ehdr e64;
    1094             :       } ehdr;
    1095           0 :       Elf_Data dst =
    1096             :         {
    1097             :           .d_buf = &ehdr,
    1098             :           .d_size = sizeof ehdr,
    1099             :           .d_type = ELF_T_EHDR,
    1100             :           .d_version = EV_CURRENT
    1101             :         };
    1102           0 :       Elf_Data src = *undodata;
    1103           0 :       src.d_size = gelf_fsize (main, ELF_T_EHDR, 1, EV_CURRENT);
    1104           0 :       src.d_type = ELF_T_EHDR;
    1105           0 :       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
    1106             :                                 main_ehdr->e_ident[EI_DATA]) != NULL,
    1107             :                  _("cannot read '.gnu.prelink_undo' section: %s"));
    1108             : 
    1109             :       uint_fast16_t phnum;
    1110             :       uint_fast16_t shnum;  /* prelink doesn't handle > SHN_LORESERVE.  */
    1111           0 :       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
    1112             :         {
    1113           0 :           phnum = ehdr.e32.e_phnum;
    1114           0 :           shnum = ehdr.e32.e_shnum;
    1115             :         }
    1116             :       else
    1117             :         {
    1118           0 :           phnum = ehdr.e64.e_phnum;
    1119           0 :           shnum = ehdr.e64.e_shnum;
    1120             :         }
    1121             : 
    1122           0 :       bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
    1123           0 :       size_t shsize = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr);
    1124           0 :       if (unlikely (shnum == 0 || shnum > SIZE_MAX / shsize + 1))
    1125           0 :         error (EXIT_FAILURE, 0, _("overflow with shnum = %zu in '%s' section"),
    1126             :                (size_t) shnum, ".gnu.prelink_undo");
    1127             : 
    1128           0 :       --shnum;
    1129             : 
    1130           0 :       size_t phsize = gelf_fsize (main, ELF_T_PHDR, phnum, EV_CURRENT);
    1131           0 :       src.d_buf += src.d_size + phsize;
    1132           0 :       src.d_size = gelf_fsize (main, ELF_T_SHDR, shnum, EV_CURRENT);
    1133           0 :       src.d_type = ELF_T_SHDR;
    1134           0 :       if ((size_t) (src.d_buf - undodata->d_buf) > undodata->d_size
    1135           0 :           || undodata->d_size - (src.d_buf - undodata->d_buf) != src.d_size)
    1136           0 :         error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"),
    1137             :                ".gnu.prelink_undo");
    1138             : 
    1139           0 :       const size_t shdr_bytes = shnum * shsize;
    1140           0 :       void *shdr = xmalloc (shdr_bytes);
    1141           0 :       dst.d_buf = shdr;
    1142           0 :       dst.d_size = shdr_bytes;
    1143           0 :       ELF_CHECK (gelf_xlatetom (main, &dst, &src,
    1144             :                                 main_ehdr->e_ident[EI_DATA]) != NULL,
    1145             :                  _("cannot read '.gnu.prelink_undo' section: %s"));
    1146             : 
    1147           0 :       undo_sections = xmalloc (shnum * sizeof undo_sections[0]);
    1148           0 :       for (size_t i = 0; i < shnum; ++i)
    1149             :         {
    1150           0 :           struct section *sec = &undo_sections[undo_nalloc];
    1151           0 :           Elf32_Shdr (*s32)[shnum] = shdr;
    1152           0 :           Elf64_Shdr (*s64)[shnum] = shdr;
    1153           0 :           if (class32)
    1154             :             {
    1155             : #define COPY(field) sec->shdr.field = (*s32)[i].field
    1156           0 :               COPY (sh_name);
    1157           0 :               COPY (sh_type);
    1158           0 :               COPY (sh_flags);
    1159           0 :               COPY (sh_addr);
    1160           0 :               COPY (sh_offset);
    1161           0 :               COPY (sh_size);
    1162           0 :               COPY (sh_link);
    1163           0 :               COPY (sh_info);
    1164           0 :               COPY (sh_addralign);
    1165           0 :               COPY (sh_entsize);
    1166             : #undef  COPY
    1167             :             }
    1168             :           else
    1169           0 :             sec->shdr = (*s64)[i];
    1170           0 :           if (sec->shdr.sh_flags & SHF_ALLOC)
    1171             :             {
    1172           0 :               sec->shdr.sh_addr += bias;
    1173           0 :               sec->name = get_section_name (i + 1, &sec->shdr, main_shstrtab);
    1174           0 :               sec->scn = elf_getscn (main, i + 1); /* Really just for ndx.  */
    1175           0 :               sec->outscn = NULL;
    1176           0 :               sec->strent = NULL;
    1177           0 :               sec->sig = get_group_sig (main, &sec->shdr);
    1178           0 :               ++undo_nalloc;
    1179             :             }
    1180             :         }
    1181           0 :       qsort (undo_sections, undo_nalloc,
    1182             :              sizeof undo_sections[0], compare_sections_nonrel);
    1183           0 :       free (shdr);
    1184             :     }
    1185             : 
    1186           0 :   bool fail = false;
    1187           0 :   inline void check_match (bool match, Elf_Scn *scn, const char *name)
    1188             :     {
    1189           0 :       if (!match)
    1190             :         {
    1191           0 :           fail = true;
    1192           0 :           error (0, 0, _("cannot find matching section for [%zu] '%s'"),
    1193             :                  elf_ndxscn (scn), name);
    1194             :         }
    1195           0 :     }
    1196             : 
    1197           0 :   Elf_Scn *scn = NULL;
    1198           0 :   while ((scn = elf_nextscn (debug, scn)) != NULL)
    1199             :     {
    1200             :       GElf_Shdr shdr_mem;
    1201           0 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1202           0 :       ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
    1203             : 
    1204           0 :       if (!(shdr->sh_flags & SHF_ALLOC))
    1205           0 :         continue;
    1206             : 
    1207           0 :       const char *name = get_section_name (elf_ndxscn (scn), shdr,
    1208             :                                            debug_shstrtab);
    1209             : 
    1210           0 :       if (undo_sections != NULL)
    1211             :         {
    1212           0 :           struct section *sec = find_alloc_section (shdr, 0, name,
    1213             :                                                     undo_sections,
    1214             :                                                     undo_nalloc);
    1215           0 :           if (sec != NULL)
    1216             :             {
    1217           0 :               sec->outscn = scn;
    1218           0 :               continue;
    1219             :             }
    1220             :         }
    1221             : 
    1222             :       /* If there is no prelink info, we are just here to find
    1223             :          the sections to give error messages about.  */
    1224           0 :       for (size_t i = 0; shdr != NULL && i < nalloc; ++i)
    1225           0 :         if (sections[i].outscn == scn)
    1226           0 :           shdr = NULL;
    1227           0 :       check_match (shdr == NULL, scn, name);
    1228             :     }
    1229             : 
    1230           0 :   if (fail)
    1231           0 :     exit (EXIT_FAILURE);
    1232             : 
    1233             :   /* Now we have lined up output sections for each of the original sections
    1234             :      before prelinking.  Translate those to the prelinked sections.
    1235             :      This matches what prelink's undo_sections does.  */
    1236             :   struct section *split_bss = NULL;
    1237           0 :   for (size_t i = 0; i < undo_nalloc; ++i)
    1238             :     {
    1239           0 :       const struct section *undo_sec = &undo_sections[i];
    1240             : 
    1241           0 :       const char *name = undo_sec->name;
    1242           0 :       scn = undo_sec->scn; /* This is just for elf_ndxscn.  */
    1243             : 
    1244           0 :       for (size_t j = 0; j < nalloc; ++j)
    1245             :         {
    1246           0 :           struct section *sec = &sections[j];
    1247             : #define RELA_SCALED(field) \
    1248             :           (2 * sec->shdr.field == 3 * undo_sec->shdr.field)
    1249           0 :           if (sec->outscn == NULL
    1250           0 :               && sec->shdr.sh_name == undo_sec->shdr.sh_name
    1251           0 :               && sec->shdr.sh_flags == undo_sec->shdr.sh_flags
    1252           0 :               && sec->shdr.sh_addralign == undo_sec->shdr.sh_addralign
    1253           0 :               && (((sec->shdr.sh_type == undo_sec->shdr.sh_type
    1254           0 :                     && sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
    1255           0 :                     && (sec->shdr.sh_size == undo_sec->shdr.sh_size
    1256           0 :                         || (sec->shdr.sh_size > undo_sec->shdr.sh_size
    1257           0 :                             && main_ehdr->e_type == ET_EXEC
    1258           0 :                             && !strcmp (sec->name, ".dynstr"))))
    1259           0 :                    || (sec->shdr.sh_size == undo_sec->shdr.sh_size
    1260           0 :                        && ((sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
    1261           0 :                             && undo_sec->shdr.sh_type == SHT_NOBITS)
    1262           0 :                            || undo_sec->shdr.sh_type == SHT_PROGBITS)
    1263           0 :                        && !strcmp (sec->name, ".plt")))
    1264           0 :                   || (sec->shdr.sh_type == SHT_RELA
    1265           0 :                       && undo_sec->shdr.sh_type == SHT_REL
    1266           0 :                       && RELA_SCALED (sh_entsize) && RELA_SCALED (sh_size))
    1267           0 :                   || (sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize
    1268           0 :                       && (sec->shdr.sh_type == undo_sec->shdr.sh_type
    1269           0 :                           || (sec->shdr.sh_type == SHT_PROGBITS
    1270           0 :                               && undo_sec->shdr.sh_type == SHT_NOBITS))
    1271           0 :                       && sec->shdr.sh_size <= undo_sec->shdr.sh_size
    1272           0 :                       && (!strcmp (sec->name, ".bss")
    1273           0 :                           || !strcmp (sec->name, ".sbss"))
    1274           0 :                       && (sec->shdr.sh_size == undo_sec->shdr.sh_size
    1275           0 :                           || (split_bss = sec) > sections))))
    1276             :             {
    1277           0 :               sec->outscn = undo_sec->outscn;
    1278           0 :               undo_sec = NULL;
    1279             :               break;
    1280             :             }
    1281             :         }
    1282             : 
    1283           0 :       check_match (undo_sec == NULL, scn, name);
    1284             :     }
    1285             : 
    1286           0 :   free (undo_sections);
    1287             : 
    1288           0 :   if (fail)
    1289           0 :     exit (EXIT_FAILURE);
    1290             : 
    1291           0 :   return split_bss;
    1292             : }
    1293             : 
    1294             : /* Create new .shstrtab contents, subroutine of copy_elided_sections.
    1295             :    This can't be open coded there and still use variable-length auto arrays,
    1296             :    since the end of our block would free other VLAs too.  */
    1297             : static Elf_Data *
    1298          20 : new_shstrtab (Elf *unstripped, size_t unstripped_shnum,
    1299             :               Elf_Data *shstrtab, size_t unstripped_shstrndx,
    1300             :               struct section *sections, size_t stripped_shnum,
    1301             :               Dwelf_Strtab *strtab)
    1302          20 : {
    1303          20 :   if (strtab == NULL)
    1304             :     return NULL;
    1305             : 
    1306           0 :   Dwelf_Strent *unstripped_strent[unstripped_shnum - 1];
    1307           0 :   memset (unstripped_strent, 0, sizeof unstripped_strent);
    1308           0 :   for (struct section *sec = sections;
    1309           0 :        sec < &sections[stripped_shnum - 1];
    1310           0 :        ++sec)
    1311           0 :     if (sec->outscn != NULL)
    1312             :       {
    1313           0 :         if (sec->strent == NULL)
    1314             :           {
    1315           0 :             sec->strent = dwelf_strtab_add (strtab, sec->name);
    1316           0 :             ELF_CHECK (sec->strent != NULL,
    1317             :                        _("cannot add section name to string table: %s"));
    1318             :           }
    1319           0 :         unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent;
    1320             :       }
    1321             : 
    1322             :   /* Add names of sections we aren't touching.  */
    1323           0 :   for (size_t i = 0; i < unstripped_shnum - 1; ++i)
    1324           0 :     if (unstripped_strent[i] == NULL)
    1325             :       {
    1326           0 :         Elf_Scn *scn = elf_getscn (unstripped, i + 1);
    1327             :         GElf_Shdr shdr_mem;
    1328           0 :         GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1329           0 :         const char *name = get_section_name (i + 1, shdr, shstrtab);
    1330           0 :         unstripped_strent[i] = dwelf_strtab_add (strtab, name);
    1331           0 :         ELF_CHECK (unstripped_strent[i] != NULL,
    1332             :                    _("cannot add section name to string table: %s"));
    1333             :       }
    1334             :     else
    1335           0 :       unstripped_strent[i] = NULL;
    1336             : 
    1337             :   /* Now finalize the string table so we can get offsets.  */
    1338           0 :   Elf_Data *strtab_data = elf_getdata (elf_getscn (unstripped,
    1339             :                                                    unstripped_shstrndx), NULL);
    1340           0 :   ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY),
    1341             :              _("cannot update section header string table data: %s"));
    1342           0 :   if (dwelf_strtab_finalize (strtab, strtab_data) == NULL)
    1343             :     error (EXIT_FAILURE, 0, "Not enough memory to create string table");
    1344             : 
    1345             :   /* Update the sh_name fields of sections we aren't modifying later.  */
    1346           0 :   for (size_t i = 0; i < unstripped_shnum - 1; ++i)
    1347           0 :     if (unstripped_strent[i] != NULL)
    1348             :       {
    1349           0 :         Elf_Scn *scn = elf_getscn (unstripped, i + 1);
    1350             :         GElf_Shdr shdr_mem;
    1351           0 :         GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1352           0 :         shdr->sh_name = dwelf_strent_off (unstripped_strent[i]);
    1353           0 :         if (i + 1 == unstripped_shstrndx)
    1354           0 :           shdr->sh_size = strtab_data->d_size;
    1355           0 :         update_shdr (scn, shdr);
    1356             :       }
    1357             : 
    1358             :   return strtab_data;
    1359             : }
    1360             : 
    1361             : /* Fill in any SHT_NOBITS sections in UNSTRIPPED by
    1362             :    copying their contents and sh_type from STRIPPED.  */
    1363             : static void
    1364          20 : copy_elided_sections (Elf *unstripped, Elf *stripped,
    1365             :                       const GElf_Ehdr *stripped_ehdr, GElf_Addr bias)
    1366          20 : {
    1367             :   size_t unstripped_shstrndx;
    1368          20 :   ELF_CHECK (elf_getshdrstrndx (unstripped, &unstripped_shstrndx) == 0,
    1369             :              _("cannot get section header string table section index: %s"));
    1370             : 
    1371             :   size_t stripped_shstrndx;
    1372          20 :   ELF_CHECK (elf_getshdrstrndx (stripped, &stripped_shstrndx) == 0,
    1373             :              _("cannot get section header string table section index: %s"));
    1374             : 
    1375             :   size_t unstripped_shnum;
    1376          20 :   ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
    1377             :              _("cannot get section count: %s"));
    1378             : 
    1379             :   size_t stripped_shnum;
    1380          20 :   ELF_CHECK (elf_getshdrnum (stripped, &stripped_shnum) == 0,
    1381             :              _("cannot get section count: %s"));
    1382             : 
    1383          20 :   if (unlikely (stripped_shnum > unstripped_shnum))
    1384           0 :     error (EXIT_FAILURE, 0, _("\
    1385             : more sections in stripped file than debug file -- arguments reversed?"));
    1386             : 
    1387             :   /* Cache the stripped file's section details.  */
    1388          20 :   struct section sections[stripped_shnum - 1];
    1389          20 :   Elf_Scn *scn = NULL;
    1390         527 :   while ((scn = elf_nextscn (stripped, scn)) != NULL)
    1391             :     {
    1392         487 :       size_t i = elf_ndxscn (scn) - 1;
    1393         487 :       GElf_Shdr *shdr = gelf_getshdr (scn, &sections[i].shdr);
    1394         487 :       ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
    1395         487 :       sections[i].name = elf_strptr (stripped, stripped_shstrndx,
    1396         487 :                                      shdr->sh_name);
    1397         487 :       if (sections[i].name == NULL)
    1398           0 :         error (EXIT_FAILURE, 0, _("cannot read section [%zu] name: %s"),
    1399             :                elf_ndxscn (scn), elf_errmsg (-1));
    1400         487 :       sections[i].scn = scn;
    1401         487 :       sections[i].outscn = NULL;
    1402         487 :       sections[i].strent = NULL;
    1403         487 :       sections[i].sig = get_group_sig (stripped, shdr);
    1404             :     }
    1405             : 
    1406          20 :   const struct section *stripped_symtab = NULL;
    1407             : 
    1408             :   /* Sort the sections, allocated by address and others after.  */
    1409          20 :   qsort (sections, stripped_shnum - 1, sizeof sections[0],
    1410          20 :          stripped_ehdr->e_type == ET_REL
    1411             :          ? compare_sections_rel : compare_sections_nonrel);
    1412          20 :   size_t nalloc = stripped_shnum - 1;
    1413         180 :   while (nalloc > 0 && !(sections[nalloc - 1].shdr.sh_flags & SHF_ALLOC))
    1414             :     {
    1415         140 :       --nalloc;
    1416         140 :       if (sections[nalloc].shdr.sh_type == SHT_SYMTAB)
    1417          10 :         stripped_symtab = &sections[nalloc];
    1418             :     }
    1419             : 
    1420             :   /* Locate a matching unallocated section in SECTIONS.  */
    1421       65799 :   inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
    1422             :                                                const char *name,
    1423             :                                                const char *sig)
    1424             :     {
    1425       65799 :       size_t l = nalloc, u = stripped_shnum - 1;
    1426      328901 :       while (l < u)
    1427             :         {
    1428      197385 :           size_t i = (l + u) / 2;
    1429      197385 :           struct section *sec = &sections[i];
    1430      197385 :           int cmp = compare_unalloc_sections (shdr, &sec->shdr,
    1431             :                                               name, sec->name,
    1432             :                                               sig, sec->sig);
    1433      197385 :           if (cmp < 0)
    1434             :             u = i;
    1435         450 :           else if (cmp > 0)
    1436         368 :             l = i + 1;
    1437             :           else
    1438             :             return sec;
    1439             :         }
    1440             :       return NULL;
    1441             :     }
    1442             : 
    1443          20 :   Elf_Data *shstrtab = elf_getdata (elf_getscn (unstripped,
    1444             :                                                 unstripped_shstrndx), NULL);
    1445          20 :   ELF_CHECK (shstrtab != NULL,
    1446             :              _("cannot read section header string table: %s"));
    1447             : 
    1448             :   /* Match each debuginfo section with its corresponding stripped section.  */
    1449             :   bool check_prelink = false;
    1450             :   Elf_Scn *unstripped_symtab = NULL;
    1451             :   size_t unstripped_strndx = 0;
    1452             :   size_t alloc_avail = 0;
    1453             :   scn = NULL;
    1454       66224 :   while ((scn = elf_nextscn (unstripped, scn)) != NULL)
    1455             :     {
    1456             :       GElf_Shdr shdr_mem;
    1457       66204 :       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    1458       66204 :       ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
    1459             : 
    1460       66204 :       if (shdr->sh_type == SHT_SYMTAB)
    1461             :         {
    1462          20 :           unstripped_symtab = scn;
    1463          20 :           unstripped_strndx = shdr->sh_link;
    1464       65795 :           continue;
    1465             :         }
    1466             : 
    1467       66184 :       const size_t ndx = elf_ndxscn (scn);
    1468       66184 :       if (ndx == unstripped_shstrndx || ndx == unstripped_strndx)
    1469          38 :         continue;
    1470             : 
    1471       66146 :       const char *name = get_section_name (ndx, shdr, shstrtab);
    1472             : 
    1473       66146 :       struct section *sec = NULL;
    1474       66146 :       if (shdr->sh_flags & SHF_ALLOC)
    1475             :         {
    1476         347 :           if (stripped_ehdr->e_type != ET_REL)
    1477             :             {
    1478             :               /* Look for the section that matches.  */
    1479         272 :               sec = find_alloc_section (shdr, bias, name, sections, nalloc);
    1480         272 :               if (sec == NULL)
    1481             :                 {
    1482             :                   /* We couldn't figure it out.  It may be a prelink issue.  */
    1483           0 :                   check_prelink = true;
    1484           0 :                   continue;
    1485             :                 }
    1486             :             }
    1487             :           else
    1488             :             {
    1489             :               /* The sh_addr of allocated sections does not help us,
    1490             :                  but the order usually matches.  */
    1491          75 :               if (likely (sections_match (sections, alloc_avail, shdr, name)))
    1492          75 :                 sec = &sections[alloc_avail++];
    1493             :               else
    1494           0 :                 for (size_t i = alloc_avail + 1; i < nalloc; ++i)
    1495           0 :                   if (sections_match (sections, i, shdr, name))
    1496             :                     {
    1497           0 :                       sec = &sections[i];
    1498           0 :                       break;
    1499             :                     }
    1500             :             }
    1501             :         }
    1502             :       else
    1503             :         {
    1504             :           /* Look for the section that matches.  */
    1505       65799 :           sec = find_unalloc_section (shdr, name,
    1506             :                                       get_group_sig (unstripped, shdr));
    1507       65799 :           if (sec == NULL)
    1508             :             {
    1509             :               /* An additional unallocated section is fine if not SHT_NOBITS.
    1510             :                  We looked it up anyway in case it's an unallocated section
    1511             :                  copied in both files (e.g. SHT_NOTE), and don't keep both.  */
    1512       65717 :               if (shdr->sh_type != SHT_NOBITS)
    1513       65717 :                 continue;
    1514             : 
    1515             :               /* Somehow some old .debug files wound up with SHT_NOBITS
    1516             :                  .comment sections, so let those pass.  */
    1517           0 :               if (!strcmp (name, ".comment"))
    1518           0 :                 continue;
    1519             :             }
    1520             :         }
    1521             : 
    1522         429 :       if (sec == NULL)
    1523           0 :         error (EXIT_FAILURE, 0,
    1524           0 :                _("cannot find matching section for [%zu] '%s'"),
    1525             :                elf_ndxscn (scn), name);
    1526             : 
    1527         429 :       sec->outscn = scn;
    1528             :     }
    1529             : 
    1530             :   /* If that failed due to changes made by prelink, we take another tack.
    1531             :      We keep track of a .bss section that was partly split into .dynbss
    1532             :      so that collect_symbols can update symbols' st_shndx fields.  */
    1533          20 :   struct section *split_bss = NULL;
    1534          20 :   if (check_prelink)
    1535             :     {
    1536           0 :       Elf_Data *data = elf_getdata (elf_getscn (stripped, stripped_shstrndx),
    1537             :                                     NULL);
    1538           0 :       ELF_CHECK (data != NULL,
    1539             :                  _("cannot read section header string table: %s"));
    1540           0 :       split_bss = find_alloc_sections_prelink (unstripped, shstrtab,
    1541             :                                                stripped, stripped_ehdr,
    1542             :                                                data, bias, sections,
    1543             :                                                nalloc, stripped_shnum - 1);
    1544             :     }
    1545             : 
    1546             :   /* Make sure each main file section has a place to go.  */
    1547          20 :   const struct section *stripped_dynsym = NULL;
    1548          20 :   size_t debuglink = SHN_UNDEF;
    1549          20 :   size_t ndx_section[stripped_shnum - 1];
    1550          20 :   Dwelf_Strtab *strtab = NULL;
    1551         527 :   for (struct section *sec = sections;
    1552         507 :        sec < &sections[stripped_shnum - 1];
    1553         487 :        ++sec)
    1554             :     {
    1555         487 :       size_t secndx = elf_ndxscn (sec->scn);
    1556             : 
    1557         487 :       if (sec->outscn == NULL)
    1558             :         {
    1559             :           /* We didn't find any corresponding section for this.  */
    1560             : 
    1561          58 :           if (secndx == stripped_shstrndx)
    1562             :             {
    1563             :               /* We only need one .shstrtab.  */
    1564          20 :               ndx_section[secndx - 1] = unstripped_shstrndx;
    1565          20 :               continue;
    1566             :             }
    1567             : 
    1568          38 :           if (unstripped_symtab != NULL && sec == stripped_symtab)
    1569             :             {
    1570             :               /* We don't need a second symbol table.  */
    1571          10 :               ndx_section[secndx - 1] = elf_ndxscn (unstripped_symtab);
    1572          10 :               continue;
    1573             :             }
    1574             : 
    1575          28 :           if (unstripped_symtab != NULL && stripped_symtab != NULL
    1576          18 :               && secndx == stripped_symtab->shdr.sh_link
    1577          10 :               && unstripped_strndx != 0)
    1578             :             {
    1579             :               /* ... nor its string table.  */
    1580          10 :               ndx_section[secndx - 1] = unstripped_strndx;
    1581          10 :               continue;
    1582             :             }
    1583             : 
    1584          18 :           if (!(sec->shdr.sh_flags & SHF_ALLOC)
    1585          18 :               && !strcmp (sec->name, ".gnu_debuglink"))
    1586             :             {
    1587             :               /* This was created by stripping.  We don't want it.  */
    1588          18 :               debuglink = secndx;
    1589          18 :               ndx_section[secndx - 1] = SHN_UNDEF;
    1590          18 :               continue;
    1591             :             }
    1592             : 
    1593           0 :           sec->outscn = elf_newscn (unstripped);
    1594           0 :           Elf_Data *newdata = elf_newdata (sec->outscn);
    1595           0 :           ELF_CHECK (newdata != NULL && gelf_update_shdr (sec->outscn,
    1596             :                                                           &sec->shdr),
    1597             :                      _("cannot add new section: %s"));
    1598             : 
    1599           0 :           if (strtab == NULL)
    1600           0 :             strtab = dwelf_strtab_init (true);
    1601           0 :           sec->strent = dwelf_strtab_add (strtab, sec->name);
    1602           0 :           ELF_CHECK (sec->strent != NULL,
    1603             :                      _("cannot add section name to string table: %s"));
    1604             :         }
    1605             : 
    1606             :       /* Cache the mapping of original section indices to output sections.  */
    1607         429 :       ndx_section[secndx - 1] = elf_ndxscn (sec->outscn);
    1608             :     }
    1609             : 
    1610             :   /* We added some sections, so we need a new shstrtab.  */
    1611          20 :   Elf_Data *strtab_data = new_shstrtab (unstripped, unstripped_shnum,
    1612             :                                         shstrtab, unstripped_shstrndx,
    1613             :                                         sections, stripped_shnum,
    1614             :                                         strtab);
    1615             : 
    1616             :   /* Get the updated section count.  */
    1617          20 :   ELF_CHECK (elf_getshdrnum (unstripped, &unstripped_shnum) == 0,
    1618             :              _("cannot get section count: %s"));
    1619             : 
    1620          20 :   bool placed[unstripped_shnum - 1];
    1621          40 :   memset (placed, 0, sizeof placed);
    1622             : 
    1623             :   /* Now update the output sections and copy in their data.  */
    1624          20 :   GElf_Off offset = 0;
    1625         527 :   for (const struct section *sec = sections;
    1626         507 :        sec < &sections[stripped_shnum - 1];
    1627         487 :        ++sec)
    1628         487 :     if (sec->outscn != NULL)
    1629             :       {
    1630             :         GElf_Shdr shdr_mem;
    1631         429 :         GElf_Shdr *shdr = gelf_getshdr (sec->outscn, &shdr_mem);
    1632         429 :         ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
    1633             : 
    1634             :         /* In an ET_REL file under --relocate, the sh_addr of SHF_ALLOC
    1635             :            sections will have been set nonzero by relocation.  This
    1636             :            touched the shdrs of whichever file had the symtab.  sh_addr
    1637             :            is still zero in the corresponding shdr.  The relocated
    1638             :            address is what we want to use.  */
    1639         429 :         if (stripped_ehdr->e_type != ET_REL
    1640         142 :             || !(shdr_mem.sh_flags & SHF_ALLOC)
    1641          75 :             || shdr_mem.sh_addr == 0)
    1642         429 :           shdr_mem.sh_addr = sec->shdr.sh_addr;
    1643             : 
    1644         429 :         shdr_mem.sh_type = sec->shdr.sh_type;
    1645         429 :         shdr_mem.sh_size = sec->shdr.sh_size;
    1646         429 :         shdr_mem.sh_info = sec->shdr.sh_info;
    1647         429 :         shdr_mem.sh_link = sec->shdr.sh_link;
    1648             : 
    1649             :         /* Buggy binutils objdump might have stripped the SHF_INFO_LINK
    1650             :            put it back if necessary.  */
    1651         429 :         if ((sec->shdr.sh_type == SHT_REL || sec->shdr.sh_type == SHT_RELA)
    1652          64 :             && sec->shdr.sh_flags != shdr_mem.sh_flags
    1653           2 :             && (sec->shdr.sh_flags & SHF_INFO_LINK) != 0)
    1654           2 :           shdr_mem.sh_flags |= SHF_INFO_LINK;
    1655             : 
    1656         429 :         if (sec->shdr.sh_link != SHN_UNDEF)
    1657         131 :           shdr_mem.sh_link = ndx_section[sec->shdr.sh_link - 1];
    1658         429 :         if (SH_INFO_LINK_P (&sec->shdr) && sec->shdr.sh_info != 0)
    1659          53 :           shdr_mem.sh_info = ndx_section[sec->shdr.sh_info - 1];
    1660             : 
    1661         429 :         if (strtab != NULL)
    1662           0 :           shdr_mem.sh_name = dwelf_strent_off (sec->strent);
    1663             : 
    1664         429 :         Elf_Data *indata = elf_getdata (sec->scn, NULL);
    1665         429 :         ELF_CHECK (indata != NULL, _("cannot get section data: %s"));
    1666         429 :         Elf_Data *outdata = elf_getdata (sec->outscn, NULL);
    1667         429 :         ELF_CHECK (outdata != NULL, _("cannot copy section data: %s"));
    1668         429 :         *outdata = *indata;
    1669         429 :         elf_flagdata (outdata, ELF_C_SET, ELF_F_DIRTY);
    1670             : 
    1671             :         /* Preserve the file layout of the allocated sections.  */
    1672         429 :         if (stripped_ehdr->e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC))
    1673             :           {
    1674         272 :             shdr_mem.sh_offset = sec->shdr.sh_offset;
    1675         272 :             placed[elf_ndxscn (sec->outscn) - 1] = true;
    1676             : 
    1677         544 :             const GElf_Off end_offset = (shdr_mem.sh_offset
    1678         272 :                                          + (shdr_mem.sh_type == SHT_NOBITS
    1679         272 :                                             ? 0 : shdr_mem.sh_size));
    1680         272 :             if (end_offset > offset)
    1681         263 :               offset = end_offset;
    1682             :           }
    1683             : 
    1684         429 :         update_shdr (sec->outscn, &shdr_mem);
    1685             : 
    1686         429 :         if (shdr_mem.sh_type == SHT_SYMTAB || shdr_mem.sh_type == SHT_DYNSYM)
    1687             :           {
    1688             :             /* We must adjust all the section indices in the symbol table.  */
    1689             : 
    1690          12 :             Elf_Data *shndxdata = NULL; /* XXX */
    1691             : 
    1692          12 :             if (shdr_mem.sh_entsize == 0)
    1693             :               error (EXIT_FAILURE, 0,
    1694             :                      "SYMTAB section cannot have zero sh_entsize");
    1695         281 :             for (size_t i = 1; i < shdr_mem.sh_size / shdr_mem.sh_entsize; ++i)
    1696             :               {
    1697             :                 GElf_Sym sym_mem;
    1698         281 :                 GElf_Word shndx = SHN_UNDEF;
    1699         281 :                 GElf_Sym *sym = gelf_getsymshndx (outdata, shndxdata,
    1700             :                                                   i, &sym_mem, &shndx);
    1701         281 :                 ELF_CHECK (sym != NULL,
    1702             :                            _("cannot get symbol table entry: %s"));
    1703         281 :                 if (sym->st_shndx != SHN_XINDEX)
    1704         281 :                   shndx = sym->st_shndx;
    1705             : 
    1706         281 :                 if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
    1707             :                   {
    1708         119 :                     if (shndx >= stripped_shnum)
    1709             :                       error (EXIT_FAILURE, 0,
    1710           0 :                              _("symbol [%zu] has invalid section index"), i);
    1711             : 
    1712         119 :                     shndx = ndx_section[shndx - 1];
    1713         119 :                     if (shndx < SHN_LORESERVE)
    1714             :                       {
    1715         119 :                         sym->st_shndx = shndx;
    1716         119 :                         shndx = SHN_UNDEF;
    1717             :                       }
    1718             :                     else
    1719           0 :                       sym->st_shndx = SHN_XINDEX;
    1720             : 
    1721         119 :                     ELF_CHECK (gelf_update_symshndx (outdata, shndxdata,
    1722             :                                                      i, sym, shndx),
    1723             :                                _("cannot update symbol table: %s"));
    1724             :                   }
    1725             :               }
    1726             : 
    1727          12 :             if (shdr_mem.sh_type == SHT_SYMTAB)
    1728           0 :               stripped_symtab = sec;
    1729          12 :             if (shdr_mem.sh_type == SHT_DYNSYM)
    1730          12 :               stripped_dynsym = sec;
    1731             :           }
    1732             : 
    1733         429 :         if (shdr_mem.sh_type == SHT_GROUP)
    1734             :           {
    1735             :             /* We must adjust all the section indices in the group.
    1736             :                Skip the first word, which is the section group flag.
    1737             :                Everything else is a section index.  */
    1738           7 :             Elf32_Word *shndx = (Elf32_Word *) outdata->d_buf;
    1739          22 :             for (size_t i = 1; i < shdr_mem.sh_size / sizeof (Elf32_Word); ++i)
    1740          15 :               if (shndx[i]  == SHN_UNDEF || shndx[i] >= stripped_shnum)
    1741             :                 error (EXIT_FAILURE, 0,
    1742           0 :                        _("group has invalid section index [%zd]"), i);
    1743             :               else
    1744          15 :                 shndx[i] = ndx_section[shndx[i] - 1];
    1745             :           }
    1746             :       }
    1747             : 
    1748             :   /* We may need to update the symbol table.  */
    1749          20 :   Elf_Data *symdata = NULL;
    1750          20 :   Dwelf_Strtab *symstrtab = NULL;
    1751          20 :   Elf_Data *symstrdata = NULL;
    1752          40 :   if (unstripped_symtab != NULL && (stripped_symtab != NULL
    1753          20 :                                     || check_prelink /* Section adjustments. */
    1754          10 :                                     || (stripped_ehdr->e_type != ET_REL
    1755          10 :                                         && bias != 0)))
    1756          20 :     {
    1757             :       /* Merge the stripped file's symbol table into the unstripped one.  */
    1758          10 :       const size_t stripped_nsym = (stripped_symtab == NULL ? 1
    1759          20 :                                     : (stripped_symtab->shdr.sh_size
    1760          10 :                                        / (stripped_symtab->shdr.sh_entsize == 0
    1761             :                                           ? 1
    1762          10 :                                           : stripped_symtab->shdr.sh_entsize)));
    1763             : 
    1764             :       GElf_Shdr shdr_mem;
    1765          10 :       GElf_Shdr *shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
    1766          10 :       ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
    1767          10 :       if (shdr->sh_entsize == 0)
    1768             :         error (EXIT_FAILURE, 0,
    1769             :                "unstripped SYMTAB section cannot have zero sh_entsize");
    1770          10 :       const size_t unstripped_nsym = shdr->sh_size / shdr->sh_entsize;
    1771             : 
    1772             :       /* First collect all the symbols from both tables.  */
    1773             : 
    1774          10 :       const size_t total_syms = stripped_nsym - 1 + unstripped_nsym - 1;
    1775          10 :       struct symbol symbols[total_syms];
    1776          10 :       size_t symndx_map[total_syms];
    1777             : 
    1778          10 :       if (stripped_symtab != NULL)
    1779          10 :         collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
    1780             :                          stripped_symtab->scn,
    1781          10 :                          elf_getscn (stripped, stripped_symtab->shdr.sh_link),
    1782             :                          stripped_nsym, 0, ndx_section,
    1783             :                          symbols, symndx_map, NULL);
    1784             : 
    1785          10 :       Elf_Scn *unstripped_strtab = elf_getscn (unstripped, shdr->sh_link);
    1786          20 :       collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
    1787             :                        unstripped_symtab, unstripped_strtab, unstripped_nsym,
    1788          10 :                        stripped_ehdr->e_type == ET_REL ? 0 : bias, NULL,
    1789             :                        &symbols[stripped_nsym - 1],
    1790          10 :                        &symndx_map[stripped_nsym - 1], split_bss);
    1791             : 
    1792             :       /* Next, sort our array of all symbols.  */
    1793          10 :       qsort (symbols, total_syms, sizeof symbols[0], compare_symbols);
    1794             : 
    1795             :       /* Now we can weed out the duplicates.  Assign remaining symbols
    1796             :          new slots, collecting a map from old indices to new.  */
    1797          10 :       size_t nsym = 0;
    1798        1005 :       for (struct symbol *s = symbols; s < &symbols[total_syms]; ++s)
    1799             :         {
    1800             :           /* Skip a section symbol for a removed section.  */
    1801         995 :           if (s->shndx == SHN_UNDEF
    1802         269 :               && GELF_ST_TYPE (s->info.info) == STT_SECTION)
    1803             :             {
    1804           2 :               s->name = NULL;        /* Mark as discarded. */
    1805           2 :               *s->map = STN_UNDEF;
    1806           2 :               s->duplicate = NULL;
    1807           2 :               continue;
    1808             :             }
    1809             : 
    1810             :           struct symbol *n = s;
    1811        1726 :           while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
    1812             :             ++n;
    1813             : 
    1814        1726 :           while (s < n)
    1815             :             {
    1816             :               /* This is a duplicate.  Its twin will get the next slot.  */
    1817         733 :               s->name = NULL;        /* Mark as discarded. */
    1818         733 :               s->duplicate = n->map;
    1819         733 :               ++s;
    1820             :             }
    1821             : 
    1822             :           /* Allocate the next slot.  */
    1823         993 :           *s->map = ++nsym;
    1824             :         }
    1825             : 
    1826             :       /* Now we sort again, to determine the order in the output.  */
    1827          10 :       qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
    1828             : 
    1829          10 :       if (nsym < total_syms)
    1830             :         /* The discarded symbols are now at the end of the table.  */
    1831          10 :         assert (symbols[nsym].name == NULL);
    1832             : 
    1833             :       /* Now a final pass updates the map with the final order,
    1834             :          and builds up the new string table.  */
    1835          10 :       symstrtab = dwelf_strtab_init (true);
    1836        1003 :       for (size_t i = 0; i < nsym; ++i)
    1837             :         {
    1838         993 :           assert (symbols[i].name != NULL);
    1839         993 :           assert (*symbols[i].map != 0);
    1840         993 :           *symbols[i].map = 1 + i;
    1841         993 :           symbols[i].strent = dwelf_strtab_add (symstrtab, symbols[i].name);
    1842             :         }
    1843             : 
    1844             :       /* Scan the discarded symbols too, just to update their slots
    1845             :          in SYMNDX_MAP to refer to their live duplicates.  */
    1846         735 :       for (size_t i = nsym; i < total_syms; ++i)
    1847             :         {
    1848         735 :           assert (symbols[i].name == NULL);
    1849         735 :           if (symbols[i].duplicate == NULL)
    1850           2 :             assert (*symbols[i].map == STN_UNDEF);
    1851             :           else
    1852             :             {
    1853         733 :               assert (*symbols[i].duplicate != STN_UNDEF);
    1854         733 :               *symbols[i].map = *symbols[i].duplicate;
    1855             :             }
    1856             :         }
    1857             : 
    1858             :       /* Now we are ready to write the new symbol table.  */
    1859          10 :       symdata = elf_getdata (unstripped_symtab, NULL);
    1860          10 :       symstrdata = elf_getdata (unstripped_strtab, NULL);
    1861          10 :       Elf_Data *shndxdata = NULL;       /* XXX */
    1862             : 
    1863             :       /* If symtab and the section header table share the string table
    1864             :          add the section names to the strtab and then (after finalizing)
    1865             :          fixup the section header sh_names.  Also dispose of the old data.  */
    1866          10 :       Dwelf_Strent *unstripped_strent[unstripped_shnum - 1];
    1867          10 :       if (unstripped_shstrndx == elf_ndxscn (unstripped_strtab))
    1868             :         {
    1869          38 :           for (size_t i = 0; i < unstripped_shnum - 1; ++i)
    1870             :             {
    1871          38 :               Elf_Scn *sec = elf_getscn (unstripped, i + 1);
    1872             :               GElf_Shdr mem;
    1873          38 :               GElf_Shdr *hdr = gelf_getshdr (sec, &mem);
    1874          38 :               const char *name = get_section_name (i + 1, hdr, shstrtab);
    1875          38 :               unstripped_strent[i] = dwelf_strtab_add (symstrtab, name);
    1876          38 :               ELF_CHECK (unstripped_strent[i] != NULL,
    1877             :                          _("cannot add section name to string table: %s"));
    1878             :             }
    1879             : 
    1880           1 :           if (strtab != NULL)
    1881             :             {
    1882           0 :               dwelf_strtab_free (strtab);
    1883           0 :               free (strtab_data->d_buf);
    1884           0 :               strtab = NULL;
    1885             :             }
    1886             :         }
    1887             : 
    1888          10 :       if (dwelf_strtab_finalize (symstrtab, symstrdata) == NULL)
    1889             :         error (EXIT_FAILURE, 0, "Not enough memory to create symbol table");
    1890             : 
    1891          10 :       elf_flagdata (symstrdata, ELF_C_SET, ELF_F_DIRTY);
    1892             : 
    1893             :       /* And update the section header names if necessary.  */
    1894          10 :       if (unstripped_shstrndx == elf_ndxscn (unstripped_strtab))
    1895             :         {
    1896          38 :           for (size_t i = 0; i < unstripped_shnum - 1; ++i)
    1897             :             {
    1898          38 :               Elf_Scn *sec = elf_getscn (unstripped, i + 1);
    1899             :               GElf_Shdr mem;
    1900          38 :               GElf_Shdr *hdr = gelf_getshdr (sec, &mem);
    1901          38 :               shdr->sh_name = dwelf_strent_off (unstripped_strent[i]);
    1902          38 :               update_shdr (sec, hdr);
    1903             :             }
    1904             :         }
    1905             : 
    1906             :       /* Now update the symtab shdr.  Reload symtab shdr because sh_name
    1907             :          might have changed above. */
    1908          10 :       shdr = gelf_getshdr (unstripped_symtab, &shdr_mem);
    1909          10 :       ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
    1910             : 
    1911          10 :       shdr->sh_size = symdata->d_size = (1 + nsym) * shdr->sh_entsize;
    1912          10 :       symdata->d_buf = xmalloc (symdata->d_size);
    1913          20 :       record_new_data (symdata->d_buf);
    1914             : 
    1915             :       GElf_Sym sym;
    1916          10 :       memset (&sym, 0, sizeof sym);
    1917          10 :       ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 0, &sym, SHN_UNDEF),
    1918             :                  _("cannot update symbol table: %s"));
    1919             : 
    1920          10 :       shdr->sh_info = 1;
    1921        1003 :       for (size_t i = 0; i < nsym; ++i)
    1922             :         {
    1923         993 :           struct symbol *s = &symbols[i];
    1924             : 
    1925             :           /* Fill in the symbol details.  */
    1926         993 :           sym.st_name = dwelf_strent_off (s->strent);
    1927         993 :           sym.st_value = s->value; /* Already biased to output address.  */
    1928         993 :           sym.st_size = s->size;
    1929         993 :           sym.st_shndx = s->shndx; /* Already mapped to output index.  */
    1930         993 :           sym.st_info = s->info.info;
    1931         993 :           sym.st_other = s->info.other;
    1932             : 
    1933             :           /* Keep track of the number of leading local symbols.  */
    1934         993 :           if (GELF_ST_BIND (sym.st_info) == STB_LOCAL)
    1935             :             {
    1936         682 :               assert (shdr->sh_info == 1 + i);
    1937         682 :               shdr->sh_info = 1 + i + 1;
    1938             :             }
    1939             : 
    1940         993 :           ELF_CHECK (gelf_update_symshndx (symdata, shndxdata, 1 + i,
    1941             :                                            &sym, SHN_UNDEF),
    1942             :                      _("cannot update symbol table: %s"));
    1943             : 
    1944             :         }
    1945          10 :       elf_flagdata (symdata, ELF_C_SET, ELF_F_DIRTY);
    1946          10 :       update_shdr (unstripped_symtab, shdr);
    1947             : 
    1948          10 :       if (stripped_symtab != NULL)
    1949             :         {
    1950             :           /* Adjust any relocations referring to the old symbol table.  */
    1951          10 :           const size_t old_sh_link = elf_ndxscn (stripped_symtab->scn);
    1952         252 :           for (const struct section *sec = sections;
    1953         242 :                sec < &sections[stripped_shnum - 1];
    1954         232 :                ++sec)
    1955         232 :             if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link)
    1956          48 :               adjust_relocs (sec->outscn, sec->scn, &sec->shdr,
    1957             :                              symndx_map, shdr);
    1958             :         }
    1959             : 
    1960             :       /* Also adjust references to the other old symbol table.  */
    1961          10 :       adjust_all_relocs (unstripped, unstripped_symtab, shdr,
    1962             :                          &symndx_map[stripped_nsym - 1]);
    1963             :     }
    1964          10 :   else if (stripped_symtab != NULL && stripped_shnum != unstripped_shnum)
    1965           0 :     check_symtab_section_symbols (unstripped,
    1966           0 :                                   stripped_ehdr->e_type == ET_REL,
    1967             :                                   stripped_symtab->scn,
    1968             :                                   unstripped_shnum, unstripped_shstrndx,
    1969             :                                   stripped_symtab->outscn,
    1970             :                                   stripped_shnum, stripped_shstrndx,
    1971             :                                   debuglink);
    1972             : 
    1973          20 :   if (stripped_dynsym != NULL)
    1974          24 :     (void) check_symtab_section_symbols (unstripped,
    1975          12 :                                          stripped_ehdr->e_type == ET_REL,
    1976             :                                          stripped_dynsym->outscn,
    1977             :                                          unstripped_shnum,
    1978             :                                          unstripped_shstrndx,
    1979             :                                          stripped_dynsym->scn, stripped_shnum,
    1980             :                                          stripped_shstrndx, debuglink);
    1981             : 
    1982             :   /* We need to preserve the layout of the stripped file so the
    1983             :      phdrs will match up.  This requires us to do our own layout of
    1984             :      the added sections.  We do manual layout even for ET_REL just
    1985             :      so we can try to match what the original probably had.  */
    1986             : 
    1987          20 :   elf_flagelf (unstripped, ELF_C_SET, ELF_F_LAYOUT);
    1988             : 
    1989          20 :   if (offset == 0)
    1990             :     /* For ET_REL we are starting the layout from scratch.  */
    1991           8 :     offset = gelf_fsize (unstripped, ELF_T_EHDR, 1, EV_CURRENT);
    1992             : 
    1993             :   bool skip_reloc = false;
    1994             :   do
    1995             :     {
    1996          40 :       skip_reloc = !skip_reloc;
    1997      132448 :       for (size_t i = 0; i < unstripped_shnum - 1; ++i)
    1998      132408 :         if (!placed[i])
    1999             :           {
    2000       66007 :             scn = elf_getscn (unstripped, 1 + i);
    2001             : 
    2002             :             GElf_Shdr shdr_mem;
    2003       66007 :             GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    2004       66007 :             ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
    2005             : 
    2006             :             /* We must make sure we have read in the data of all sections
    2007             :                beforehand and marked them to be written out.  When we're
    2008             :                modifying the existing file in place, we might overwrite
    2009             :                this part of the file before we get to handling the section.  */
    2010             : 
    2011       66007 :             ELF_CHECK (elf_flagdata (elf_getdata (scn, NULL),
    2012             :                                      ELF_C_SET, ELF_F_DIRTY),
    2013             :                        _("cannot read section data: %s"));
    2014             : 
    2015       66007 :             if (skip_reloc
    2016       65932 :                 && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
    2017          75 :               continue;
    2018             : 
    2019       65932 :             GElf_Off align = shdr->sh_addralign ?: 1;
    2020       65932 :             offset = (offset + align - 1) & -align;
    2021       65932 :             shdr->sh_offset = offset;
    2022       65932 :             if (shdr->sh_type != SHT_NOBITS)
    2023       65924 :               offset += shdr->sh_size;
    2024             : 
    2025       65932 :             update_shdr (scn, shdr);
    2026             : 
    2027       65932 :             if (unstripped_shstrndx == 1 + i)
    2028             :               {
    2029             :                 /* Place the section headers immediately after
    2030             :                    .shstrtab, and update the ELF header.  */
    2031             : 
    2032             :                 GElf_Ehdr ehdr_mem;
    2033          20 :                 GElf_Ehdr *ehdr = gelf_getehdr (unstripped, &ehdr_mem);
    2034          20 :                 ELF_CHECK (ehdr != NULL, _("cannot get ELF header: %s"));
    2035             : 
    2036          20 :                 GElf_Off sh_align = gelf_getclass (unstripped) * 4;
    2037          20 :                 offset = (offset + sh_align - 1) & -sh_align;
    2038          20 :                 ehdr->e_shnum = unstripped_shnum;
    2039          20 :                 ehdr->e_shoff = offset;
    2040          20 :                 offset += unstripped_shnum * ehdr->e_shentsize;
    2041          20 :                 ELF_CHECK (gelf_update_ehdr (unstripped, ehdr),
    2042             :                            _("cannot update ELF header: %s"));
    2043             :               }
    2044             : 
    2045       65932 :             placed[i] = true;
    2046             :           }
    2047             :     }
    2048          40 :   while (skip_reloc);
    2049             : 
    2050             :   size_t phnum;
    2051          20 :   ELF_CHECK (elf_getphdrnum (stripped, &phnum) == 0,
    2052             :              _("cannot get number of program headers: %s"));
    2053             : 
    2054          20 :   if (phnum > 0)
    2055          12 :     ELF_CHECK (gelf_newphdr (unstripped, phnum),
    2056             :                _("cannot create program headers: %s"));
    2057             : 
    2058             :   /* Copy each program header from the stripped file.  */
    2059          84 :   for (size_t i = 0; i < phnum; ++i)
    2060             :     {
    2061             :       GElf_Phdr phdr_mem;
    2062          84 :       GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
    2063          84 :       ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
    2064             : 
    2065          84 :       ELF_CHECK (gelf_update_phdr (unstripped, i, phdr),
    2066             :                  _("cannot update program header: %s"));
    2067             :     }
    2068             : 
    2069             :   /* Finally, write out the file.  */
    2070          20 :   ELF_CHECK (elf_update (unstripped, ELF_C_WRITE) > 0,
    2071             :              _("cannot write output file: %s"));
    2072             : 
    2073          20 :   if (strtab != NULL)
    2074             :     {
    2075           0 :       dwelf_strtab_free (strtab);
    2076           0 :       free (strtab_data->d_buf);
    2077             :     }
    2078             : 
    2079          20 :   if (symstrtab != NULL)
    2080             :     {
    2081          10 :       dwelf_strtab_free (symstrtab);
    2082          10 :       free (symstrdata->d_buf);
    2083             :     }
    2084          20 :   free_new_data ();
    2085          20 : }
    2086             : 
    2087             : /* Process one pair of files, already opened.  */
    2088             : static void
    2089          20 : handle_file (const char *output_file, bool create_dirs,
    2090             :              Elf *stripped, const GElf_Ehdr *stripped_ehdr,
    2091             :              Elf *unstripped)
    2092             : {
    2093             :   size_t phnum;
    2094          20 :   ELF_CHECK (elf_getphdrnum (stripped, &phnum) == 0,
    2095             :              _("cannot get number of program headers: %s"));
    2096             : 
    2097             :   /* Determine the address bias between the debuginfo file and the main
    2098             :      file, which may have been modified by prelinking.  */
    2099          20 :   GElf_Addr bias = 0;
    2100          20 :   if (unstripped != NULL)
    2101          16 :     for (size_t i = 0; i < phnum; ++i)
    2102             :       {
    2103             :         GElf_Phdr phdr_mem;
    2104          28 :         GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem);
    2105          28 :         ELF_CHECK (phdr != NULL, _("cannot get program header: %s"));
    2106          28 :         if (phdr->p_type == PT_LOAD)
    2107             :           {
    2108             :             GElf_Phdr unstripped_phdr_mem;
    2109          12 :             GElf_Phdr *unstripped_phdr = gelf_getphdr (unstripped, i,
    2110             :                                                        &unstripped_phdr_mem);
    2111          12 :             ELF_CHECK (unstripped_phdr != NULL,
    2112             :                        _("cannot get program header: %s"));
    2113          12 :             bias = phdr->p_vaddr - unstripped_phdr->p_vaddr;
    2114             :             break;
    2115             :           }
    2116             :       }
    2117             : 
    2118             :   /* One day we could adjust all the DWARF data (like prelink itself does).  */
    2119          20 :   if (bias != 0)
    2120             :     {
    2121           0 :       if (output_file == NULL)
    2122           0 :         error (0, 0, _("\
    2123             : DWARF data not adjusted for prelinking bias; consider prelink -u"));
    2124             :       else
    2125           0 :         error (0, 0, _("\
    2126             : DWARF data in '%s' not adjusted for prelinking bias; consider prelink -u"),
    2127             :                output_file);
    2128             :     }
    2129             : 
    2130          20 :   if (output_file == NULL)
    2131             :     /* Modify the unstripped file in place.  */
    2132           4 :     copy_elided_sections (unstripped, stripped, stripped_ehdr, bias);
    2133             :   else
    2134             :     {
    2135          16 :       if (create_dirs)
    2136           0 :         make_directories (output_file);
    2137             : 
    2138             :       /* Copy the unstripped file and then modify it.  */
    2139          32 :       int outfd = open (output_file, O_RDWR | O_CREAT,
    2140          16 :                           stripped_ehdr->e_type == ET_REL ? 0666 : 0777);
    2141          16 :       if (outfd < 0)
    2142           0 :         error (EXIT_FAILURE, errno, _("cannot open '%s'"), output_file);
    2143          16 :       Elf *outelf = elf_begin (outfd, ELF_C_WRITE, NULL);
    2144          16 :       ELF_CHECK (outelf != NULL, _("cannot create ELF descriptor: %s"));
    2145             : 
    2146          16 :       if (unstripped == NULL)
    2147             :         {
    2148             :           /* Actually, we are just copying out the main file as it is.  */
    2149           0 :           copy_elf (outelf, stripped);
    2150           0 :           if (stripped_ehdr->e_type != ET_REL)
    2151           0 :             elf_flagelf (outelf, ELF_C_SET, ELF_F_LAYOUT);
    2152           0 :           ELF_CHECK (elf_update (outelf, ELF_C_WRITE) > 0,
    2153             :                      _("cannot write output file: %s"));
    2154             :         }
    2155             :       else
    2156             :         {
    2157          16 :           copy_elf (outelf, unstripped);
    2158          16 :           copy_elided_sections (outelf, stripped, stripped_ehdr, bias);
    2159             :         }
    2160             : 
    2161          16 :       elf_end (outelf);
    2162          16 :       close (outfd);
    2163             :     }
    2164          20 : }
    2165             : 
    2166             : static int
    2167          40 : open_file (const char *file, bool writable)
    2168             : {
    2169          80 :   int fd = open (file, writable ? O_RDWR : O_RDONLY);
    2170          40 :   if (fd < 0)
    2171           0 :     error (EXIT_FAILURE, errno, _("cannot open '%s'"), file);
    2172          40 :   return fd;
    2173             : }
    2174             : 
    2175             : /* Handle a pair of files we need to open by name.  */
    2176             : static void
    2177          20 : handle_explicit_files (const char *output_file, bool create_dirs, bool force,
    2178             :                        const char *stripped_file, const char *unstripped_file)
    2179             : {
    2180             : 
    2181             :   /* Warn, and exit if not forced to continue, if some ELF header
    2182             :      sanity check for the stripped and unstripped files failed.  */
    2183           0 :   void warn (const char *msg)
    2184             :   {
    2185           0 :     error (force ? 0 : EXIT_FAILURE, 0, "%s'%s' and '%s' %s%s.",
    2186             :            force ? _("WARNING: ") : "",
    2187             :            stripped_file, unstripped_file, msg,
    2188             :            force ? "" : _(", use --force"));
    2189           0 :   }
    2190             : 
    2191          20 :   int stripped_fd = open_file (stripped_file, false);
    2192          20 :   Elf *stripped = elf_begin (stripped_fd, ELF_C_READ, NULL);
    2193             :   GElf_Ehdr stripped_ehdr;
    2194          20 :   ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
    2195             :              _("cannot create ELF descriptor: %s"));
    2196             : 
    2197          20 :   int unstripped_fd = -1;
    2198          20 :   Elf *unstripped = NULL;
    2199          20 :   if (unstripped_file != NULL)
    2200             :     {
    2201          20 :       unstripped_fd = open_file (unstripped_file, output_file == NULL);
    2202          20 :       unstripped = elf_begin (unstripped_fd,
    2203             :                               (output_file == NULL ? ELF_C_RDWR : ELF_C_READ),
    2204             :                               NULL);
    2205             :       GElf_Ehdr unstripped_ehdr;
    2206          20 :       ELF_CHECK (gelf_getehdr (unstripped, &unstripped_ehdr),
    2207             :                  _("cannot create ELF descriptor: %s"));
    2208             : 
    2209          20 :       if (memcmp (stripped_ehdr.e_ident,
    2210             :                   unstripped_ehdr.e_ident, EI_NIDENT) != 0)
    2211           0 :         warn (_("ELF header identification (e_ident) different"));
    2212             : 
    2213          20 :       if (stripped_ehdr.e_type != unstripped_ehdr.e_type)
    2214           0 :         warn (_("ELF header type (e_type) different"));
    2215             : 
    2216          20 :       if (stripped_ehdr.e_machine != unstripped_ehdr.e_machine)
    2217           0 :         warn (_("ELF header machine type (e_machine) different"));
    2218             : 
    2219          20 :       if (stripped_ehdr.e_phnum < unstripped_ehdr.e_phnum)
    2220           0 :         warn (_("stripped program header (e_phnum) smaller than unstripped"));
    2221             :     }
    2222             : 
    2223          20 :   handle_file (output_file, create_dirs, stripped, &stripped_ehdr, unstripped);
    2224             : 
    2225          20 :   elf_end (stripped);
    2226          20 :   close (stripped_fd);
    2227             : 
    2228          20 :   elf_end (unstripped);
    2229          20 :   close (unstripped_fd);
    2230          20 : }
    2231             : 
    2232             : 
    2233             : /* Handle a pair of files opened implicitly by libdwfl for one module.  */
    2234             : static void
    2235           0 : handle_dwfl_module (const char *output_file, bool create_dirs, bool force,
    2236             :                     Dwfl_Module *mod, bool all, bool ignore, bool relocate)
    2237             : {
    2238             :   GElf_Addr bias;
    2239           0 :   Elf *stripped = dwfl_module_getelf (mod, &bias);
    2240           0 :   if (stripped == NULL)
    2241             :     {
    2242           0 :       if (ignore)
    2243           0 :         return;
    2244             : 
    2245             :       const char *file;
    2246           0 :       const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
    2247             :                                               NULL, NULL, &file, NULL);
    2248           0 :       if (file == NULL)
    2249           0 :         error (EXIT_FAILURE, 0,
    2250           0 :                _("cannot find stripped file for module '%s': %s"),
    2251             :                modname, dwfl_errmsg (-1));
    2252             :       else
    2253           0 :         error (EXIT_FAILURE, 0,
    2254           0 :                _("cannot open stripped file '%s' for module '%s': %s"),
    2255             :                modname, file, dwfl_errmsg (-1));
    2256             :     }
    2257             : 
    2258           0 :   Elf *debug = dwarf_getelf (dwfl_module_getdwarf (mod, &bias));
    2259           0 :   if (debug == NULL && !all)
    2260             :     {
    2261           0 :       if (ignore)
    2262           0 :         return;
    2263             : 
    2264             :       const char *file;
    2265           0 :       const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
    2266             :                                               NULL, NULL, NULL, &file);
    2267           0 :       if (file == NULL)
    2268           0 :         error (EXIT_FAILURE, 0,
    2269           0 :                _("cannot find debug file for module '%s': %s"),
    2270             :                modname, dwfl_errmsg (-1));
    2271             :       else
    2272           0 :         error (EXIT_FAILURE, 0,
    2273           0 :                _("cannot open debug file '%s' for module '%s': %s"),
    2274             :                modname, file, dwfl_errmsg (-1));
    2275             :     }
    2276             : 
    2277           0 :   if (debug == stripped)
    2278             :     {
    2279           0 :       if (all)
    2280             :         debug = NULL;
    2281             :       else
    2282             :         {
    2283             :           const char *file;
    2284           0 :           const char *modname = dwfl_module_info (mod, NULL, NULL, NULL,
    2285             :                                                   NULL, NULL, &file, NULL);
    2286           0 :           error (EXIT_FAILURE, 0, _("module '%s' file '%s' is not stripped"),
    2287             :                  modname, file);
    2288             :         }
    2289             :     }
    2290             : 
    2291             :   GElf_Ehdr stripped_ehdr;
    2292           0 :   ELF_CHECK (gelf_getehdr (stripped, &stripped_ehdr),
    2293             :              _("cannot create ELF descriptor: %s"));
    2294             : 
    2295           0 :   if (stripped_ehdr.e_type == ET_REL)
    2296             :     {
    2297           0 :       if (!relocate)
    2298             :         {
    2299             :           /* We can't use the Elf handles already open,
    2300             :              because the DWARF sections have been relocated.  */
    2301             : 
    2302           0 :           const char *stripped_file = NULL;
    2303           0 :           const char *unstripped_file = NULL;
    2304           0 :           (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL,
    2305             :                                    &stripped_file, &unstripped_file);
    2306             : 
    2307           0 :           handle_explicit_files (output_file, create_dirs, force,
    2308             :                                  stripped_file, unstripped_file);
    2309             :           return;
    2310             :         }
    2311             : 
    2312             :       /* Relocation is what we want!  This ensures that all sections that can
    2313             :          get sh_addr values assigned have them, even ones not used in DWARF.
    2314             :          They might still be used in the symbol table.  */
    2315           0 :       if (dwfl_module_relocations (mod) < 0)
    2316           0 :         error (EXIT_FAILURE, 0,
    2317           0 :                _("cannot cache section addresses for module '%s': %s"),
    2318             :                dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
    2319             :                dwfl_errmsg (-1));
    2320             :     }
    2321             : 
    2322           0 :   handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug);
    2323             : }
    2324             : 
    2325             : /* Handle one module being written to the output directory.  */
    2326             : static void
    2327           0 : handle_output_dir_module (const char *output_dir, Dwfl_Module *mod, bool force,
    2328             :                           bool all, bool ignore, bool modnames, bool relocate)
    2329             : {
    2330           0 :   if (! modnames)
    2331             :     {
    2332             :       /* Make sure we've searched for the ELF file.  */
    2333             :       GElf_Addr bias;
    2334           0 :       (void) dwfl_module_getelf (mod, &bias);
    2335             :     }
    2336             : 
    2337             :   const char *file;
    2338           0 :   const char *name = dwfl_module_info (mod, NULL, NULL, NULL,
    2339             :                                        NULL, NULL, &file, NULL);
    2340             : 
    2341           0 :   if (file == NULL && ignore)
    2342           0 :     return;
    2343             : 
    2344             :   char *output_file;
    2345           0 :   if (asprintf (&output_file, "%s/%s", output_dir, modnames ? name : file) < 0)
    2346           0 :     error (EXIT_FAILURE, 0, _("memory exhausted"));
    2347             : 
    2348           0 :   handle_dwfl_module (output_file, true, force, mod, all, ignore, relocate);
    2349             : }
    2350             : 
    2351             : 
    2352             : static void
    2353          17 : list_module (Dwfl_Module *mod)
    2354             : {
    2355             :   /* Make sure we have searched for the files.  */
    2356             :   GElf_Addr bias;
    2357          17 :   bool have_elf = dwfl_module_getelf (mod, &bias) != NULL;
    2358          17 :   bool have_dwarf = dwfl_module_getdwarf (mod, &bias) != NULL;
    2359             : 
    2360             :   const char *file;
    2361             :   const char *debug;
    2362             :   Dwarf_Addr start;
    2363             :   Dwarf_Addr end;
    2364          17 :   const char *name = dwfl_module_info (mod, NULL, &start, &end,
    2365             :                                        NULL, NULL, &file, &debug);
    2366          17 :   if (file != NULL && debug != NULL && (debug == file || !strcmp (debug, file)))
    2367           0 :     debug = ".";
    2368             : 
    2369             :   const unsigned char *id;
    2370             :   GElf_Addr id_vaddr;
    2371          17 :   int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
    2372             : 
    2373          34 :   printf ("%#" PRIx64 "+%#" PRIx64 " ", start, end - start);
    2374             : 
    2375          17 :   if (id_len > 0)
    2376             :     {
    2377             :       do
    2378         520 :         printf ("%02" PRIx8, *id++);
    2379         260 :       while (--id_len > 0);
    2380          13 :       if (id_vaddr != 0)
    2381          13 :         printf ("@%#" PRIx64, id_vaddr);
    2382             :     }
    2383             :   else
    2384             :     putchar ('-');
    2385             : 
    2386          51 :   printf (" %s %s %s\n",
    2387          17 :           file ?: have_elf ? "." : "-",
    2388          17 :           debug ?: have_dwarf ? "." : "-",
    2389             :           name);
    2390          17 : }
    2391             : 
    2392             : 
    2393             : struct match_module_info
    2394             : {
    2395             :   char **patterns;
    2396             :   Dwfl_Module *found;
    2397             :   bool match_files;
    2398             : };
    2399             : 
    2400             : static int
    2401          17 : match_module (Dwfl_Module *mod,
    2402             :               void **userdata __attribute__ ((unused)),
    2403             :               const char *name,
    2404             :               Dwarf_Addr start __attribute__ ((unused)),
    2405             :               void *arg)
    2406             : {
    2407          17 :   struct match_module_info *info = arg;
    2408             : 
    2409          17 :   if (info->patterns[0] == NULL) /* Match all.  */
    2410             :     {
    2411          17 :     match:
    2412          17 :       info->found = mod;
    2413          17 :       return DWARF_CB_ABORT;
    2414             :     }
    2415             : 
    2416           0 :   if (info->match_files)
    2417             :     {
    2418             :       /* Make sure we've searched for the ELF file.  */
    2419             :       GElf_Addr bias;
    2420           0 :       (void) dwfl_module_getelf (mod, &bias);
    2421             : 
    2422             :       const char *file;
    2423           0 :       const char *check = dwfl_module_info (mod, NULL, NULL, NULL,
    2424             :                                             NULL, NULL, &file, NULL);
    2425           0 :       assert (check == name);
    2426           0 :       if (file == NULL)
    2427           0 :         return DWARF_CB_OK;
    2428             : 
    2429           0 :       name = file;
    2430             :     }
    2431             : 
    2432           0 :   for (char **p = info->patterns; *p != NULL; ++p)
    2433           0 :     if (fnmatch (*p, name, 0) == 0)
    2434             :       goto match;
    2435             : 
    2436             :   return DWARF_CB_OK;
    2437             : }
    2438             : 
    2439             : /* Handle files opened implicitly via libdwfl.  */
    2440             : static void
    2441           4 : handle_implicit_modules (const struct arg_info *info)
    2442             : {
    2443           4 :   struct match_module_info mmi = { info->args, NULL, info->match_files };
    2444             :   inline ptrdiff_t next (ptrdiff_t offset)
    2445             :     {
    2446          21 :       return dwfl_getmodules (info->dwfl, &match_module, &mmi, offset);
    2447             :     }
    2448           4 :   ptrdiff_t offset = next (0);
    2449           4 :   if (offset == 0)
    2450           0 :     error (EXIT_FAILURE, 0, _("no matching modules found"));
    2451             : 
    2452           4 :   if (info->list)
    2453             :     do
    2454          17 :       list_module (mmi.found);
    2455          17 :     while ((offset = next (offset)) > 0);
    2456           0 :   else if (info->output_dir == NULL)
    2457             :     {
    2458           0 :       if (next (offset) != 0)
    2459           0 :         error (EXIT_FAILURE, 0, _("matched more than one module"));
    2460           0 :       handle_dwfl_module (info->output_file, false, info->force, mmi.found,
    2461           0 :                           info->all, info->ignore, info->relocate);
    2462             :     }
    2463             :   else
    2464             :     do
    2465           0 :       handle_output_dir_module (info->output_dir, mmi.found, info->force,
    2466           0 :                                 info->all, info->ignore,
    2467           0 :                                 info->modnames, info->relocate);
    2468           0 :     while ((offset = next (offset)) > 0);
    2469           4 : }
    2470             : 
    2471             : int
    2472          24 : main (int argc, char **argv)
    2473             : {
    2474             :   /* We use no threads here which can interfere with handling a stream.  */
    2475          24 :   __fsetlocking (stdin, FSETLOCKING_BYCALLER);
    2476          24 :   __fsetlocking (stdout, FSETLOCKING_BYCALLER);
    2477          24 :   __fsetlocking (stderr, FSETLOCKING_BYCALLER);
    2478             : 
    2479             :   /* Set locale.  */
    2480          24 :   setlocale (LC_ALL, "");
    2481             : 
    2482             :   /* Make sure the message catalog can be found.  */
    2483          24 :   bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
    2484             : 
    2485             :   /* Initialize the message catalog.  */
    2486          24 :   textdomain (PACKAGE_TARNAME);
    2487             : 
    2488             :   /* Parse and process arguments.  */
    2489          48 :   const struct argp_child argp_children[] =
    2490             :     {
    2491             :       {
    2492          24 :         .argp = dwfl_standard_argp (),
    2493             :         .header = N_("Input selection options:"),
    2494             :         .group = 1,
    2495             :       },
    2496             :       { .argp = NULL },
    2497             :     };
    2498          24 :   const struct argp argp =
    2499             :     {
    2500             :       .options = options,
    2501             :       .parser = parse_opt,
    2502             :       .children = argp_children,
    2503             :       .args_doc = N_("STRIPPED-FILE DEBUG-FILE\n[MODULE...]"),
    2504             :       .doc = N_("\
    2505             : Combine stripped files with separate symbols and debug information.\n\
    2506             : \n\
    2507             : The first form puts the result in DEBUG-FILE if -o was not given.\n\
    2508             : \n\
    2509             : MODULE arguments give file name patterns matching modules to process.\n\
    2510             : With -f these match the file name of the main (stripped) file \
    2511             : (slashes are never special), otherwise they match the simple module names.  \
    2512             : With no arguments, process all modules found.\n\
    2513             : \n\
    2514             : Multiple modules are written to files under OUTPUT-DIRECTORY, \
    2515             : creating subdirectories as needed.  \
    2516             : With -m these files have simple module names, otherwise they have the \
    2517             : name of the main file complete with directory underneath OUTPUT-DIRECTORY.\n\
    2518             : \n\
    2519             : With -n no files are written, but one line to standard output for each module:\
    2520             : \n\tSTART+SIZE BUILDID FILE DEBUGFILE MODULENAME\n\
    2521             : START and SIZE are hexadecimal giving the address bounds of the module.  \
    2522             : BUILDID is hexadecimal for the build ID bits, or - if no ID is known; \
    2523             : the hexadecimal may be followed by @0xADDR giving the address where the \
    2524             : ID resides if that is known.  \
    2525             : FILE is the file name found for the module, or - if none was found, \
    2526             : or . if an ELF image is available but not from any named file.  \
    2527             : DEBUGFILE is the separate debuginfo file name, \
    2528             : or - if no debuginfo was found, or . if FILE contains the debug information.\
    2529             : ")
    2530             :     };
    2531             : 
    2532             :   int remaining;
    2533          24 :   struct arg_info info = { .args = NULL };
    2534          24 :   error_t result = argp_parse (&argp, argc, argv, 0, &remaining, &info);
    2535          24 :   if (result == ENOSYS)
    2536          20 :     assert (info.dwfl == NULL);
    2537           4 :   else if (result)
    2538             :     return EXIT_FAILURE;
    2539          24 :   assert (info.args != NULL);
    2540             : 
    2541             :   /* Tell the library which version we are expecting.  */
    2542          24 :   elf_version (EV_CURRENT);
    2543             : 
    2544          24 :   if (info.dwfl == NULL)
    2545             :     {
    2546          20 :       assert (result == ENOSYS);
    2547             : 
    2548          20 :       if (info.output_dir != NULL)
    2549             :         {
    2550             :           char *file;
    2551           0 :           if (asprintf (&file, "%s/%s", info.output_dir, info.args[0]) < 0)
    2552           0 :             error (EXIT_FAILURE, 0, _("memory exhausted"));
    2553           0 :           handle_explicit_files (file, true, info.force,
    2554           0 :                                  info.args[0], info.args[1]);
    2555           0 :           free (file);
    2556             :         }
    2557             :       else
    2558          20 :         handle_explicit_files (info.output_file, false, info.force,
    2559          20 :                                info.args[0], info.args[1]);
    2560             :     }
    2561             :   else
    2562             :     {
    2563             :       /* parse_opt checked this.  */
    2564           4 :       assert (info.output_file != NULL || info.output_dir != NULL || info.list);
    2565             : 
    2566           4 :       handle_implicit_modules (&info);
    2567             : 
    2568           4 :       dwfl_end (info.dwfl);
    2569             :     }
    2570             : 
    2571             :   return 0;
    2572             : }
    2573             : 
    2574             : 
    2575             : #include "debugpred.h"

Generated by: LCOV version 1.13