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

Generated by: LCOV version 1.12