LCOV - code coverage report
Current view: top level - src - unstrip.c (source / functions) Hit Total Coverage
Test: elfutils-0.179 Lines: 730 1225 59.6 %
Date: 2020-03-30 14:24:38 Functions: 28 40 70.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13