]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
src/
authorRoland McGrath <roland@redhat.com>
Fri, 11 Apr 2008 07:01:58 +0000 (07:01 +0000)
committerRoland McGrath <roland@redhat.com>
Fri, 11 Apr 2008 07:01:58 +0000 (07:01 +0000)
* strip.c (handle_elf): Don't keep sections that kept symbol tables
refer to.  Instead, just be sure to preserve the original symbol
table in the debug file so those symbols go with their sections and
can be elided from the stripped version of the symbol table.

tests/
* testfile48.bz2, testfile48.bz2.debug: New data files.
* Makefile.am (EXTRA_DIST): Add them.
* run-strip-test8.sh: Use them.

12 files changed:
src/ChangeLog
src/elflint.c
src/strip.c
tests/ChangeLog
tests/Makefile.am
tests/run-strip-test.sh
tests/run-strip-test8.sh [new file with mode: 0755]
tests/testfile16.bz2
tests/testfile16.debug.bz2
tests/testfile47.bz2 [new file with mode: 0644]
tests/testfile48.bz2 [new file with mode: 0644]
tests/testfile48.debug.bz2 [new file with mode: 0644]

index 41267ea0fd5241f93278c5f9798ce3e96a34380f..94444c581cbe1f4830e9496c30007c1b090b7b63 100644 (file)
@@ -1,3 +1,22 @@
+2008-04-10  Roland McGrath  <roland@redhat.com>
+
+       * strip.c (handle_elf): Don't keep sections that kept symbol tables
+       refer to.  Instead, just be sure to preserve the original symbol
+       table in the debug file so those symbols go with their sections and
+       can be elided from the stripped version of the symbol table.
+
+       * strip.c (handle_elf): When a discarded section kept in the debug
+       file refers to a nondiscard section via sh_link/sh_info, preserve
+       that nondiscarded section unmodified in the debug file as well.
+       Skip adjustment of discarded sections symbol table references when
+       that symbol table is copied in this way.
+
+       * elflint.c (check_symtab): Don't crash from missing symbol names
+       after diagnosing bogus strtab.
+
+       * strip.c (handle_elf): Cosmetic cleanup in special section contents
+       adjustment for symtab changes.
+
 2008-03-31  Roland McGrath  <roland@redhat.com>
 
        * elflint.c (check_sections): Add checks on SHF_EXECINSTR sections:
index b13dfdb5f3e74d5cb8e4bc395eef255209e85b5d..bc4219b3e11640d9a75b568c59e99c50a97423d9 100644 (file)
@@ -579,9 +579,12 @@ check_symtab (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
     return;
 
   if (strshdr->sh_type != SHT_STRTAB)
-    ERROR (gettext ("section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"),
-          shdr->sh_link, section_name (ebl, shdr->sh_link),
-          idx, section_name (ebl, idx));
+    {
+      ERROR (gettext ("section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"),
+            shdr->sh_link, section_name (ebl, shdr->sh_link),
+            idx, section_name (ebl, idx));
+      strshdr = NULL;
+    }
 
   /* Search for an extended section index table section.  */
   Elf_Data *xndxdata = NULL;
@@ -659,7 +662,9 @@ section [%2d] '%s': XINDEX for zeroth entry not zero\n"),
        }
 
       const char *name = NULL;
-      if (sym->st_name >= strshdr->sh_size)
+      if (strshdr == NULL)
+       name = "";
+      else if (sym->st_name >= strshdr->sh_size)
        ERROR (gettext ("\
 section [%2d] '%s': symbol %zu: invalid name value\n"),
               idx, section_name (ebl, idx), cnt);
index 5fddeeebd402dadf4a60e36a8590d7090f3b00aa..0f83e61d2a2694a48a054e79823d0d5c3a870453 100644 (file)
@@ -1,5 +1,5 @@
 /* Discard section not used at runtime from object files.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
+   Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007,2008 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
@@ -390,6 +390,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
     Elf_Scn *scn;
     GElf_Shdr shdr;
     Elf_Data *data;
+    Elf_Data *debug_data;
     const char *name;
     Elf32_Word idx;            /* Index in new file.  */
     Elf32_Word old_sh_link;    /* Original value of shdr.sh_link.  */
@@ -720,8 +721,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
              /* The content of symbol tables we don't remove must not
                 reference any section which we do remove.  Otherwise
                 we cannot remove the section.  */
-             if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
-                 || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
+             if (debug_fname != NULL
+                 && shdr_info[cnt].debug_data == NULL
+                 && (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
+                     || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB))
                {
                  /* Make sure the data is loaded.  */
                  if (shdr_info[cnt].data == NULL)
@@ -779,11 +782,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                        scnidx = xndx;
 
                      if (shdr_info[scnidx].idx == 0)
-                       {
-                         /* Mark this section as used.  */
-                         shdr_info[scnidx].idx = 1;
-                         changes |= scnidx < cnt;
-                       }
+                       /* This symbol table has a real symbol in
+                          a discarded section.  So preserve the
+                          original table in the debug file.  */
+                       shdr_info[cnt].debug_data = symdata;
                    }
                }
 
@@ -819,6 +821,36 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
              /* Mark the section as investigated.  */
              shdr_info[cnt].idx = 2;
            }
+
+         if (debug_fname != NULL
+             && (shdr_info[cnt].idx == 0 || shdr_info[cnt].debug_data != NULL))
+           {
+             /* This section is being preserved in the debug file.
+                Sections it refers to must be preserved there too.
+
+                In this pass we mark sections to be preserved in both
+                files by setting the .debug_data pointer to the original
+                file's .data pointer.  Below, we'll copy the section
+                contents.  */
+
+             inline void check_preserved (size_t i)
+             {
+               if (i != 0 && shdr_info[i].idx != 0)
+                 {
+                   if (shdr_info[i].data == NULL)
+                     shdr_info[i].data = elf_getdata (shdr_info[i].scn, NULL);
+                   if (shdr_info[i].data == NULL)
+                     INTERNAL_ERROR (fname);
+
+                   shdr_info[i].debug_data = shdr_info[i].data;
+                   changes |= i < cnt;
+                 }
+             }
+
+             check_preserved (shdr_info[cnt].shdr.sh_link);
+             if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
+               check_preserved (shdr_info[cnt].shdr.sh_info);
+           }
        }
     }
   while (changes);
@@ -836,6 +868,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                   elf_errmsg (-1));
 
          bool discard_section = (shdr_info[cnt].idx > 0
+                                 && shdr_info[cnt].debug_data == NULL
                                  && shdr_info[cnt].shdr.sh_type != SHT_NOTE
                                  && cnt != ehdr->e_shstrndx);
 
@@ -866,6 +899,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
          *debugdata = *shdr_info[cnt].data;
          if (discard_section)
            debugdata->d_buf = NULL;
+         else if (shdr_info[cnt].debug_data != NULL)
+           {
+             /* Copy the original data before it gets modified.  */
+             shdr_info[cnt].debug_data = debugdata;
+             debugdata->d_buf = memcpy (xmalloc (debugdata->d_size),
+                                        debugdata->d_buf, debugdata->d_size);
+           }
        }
 
       /* Finish the ELF header.  Fill in the fields not handled by
@@ -1078,7 +1118,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            /* We know the size.  */
            shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size;
 
-           /* We have to adjust symtol tables.  The st_shndx member might
+           /* We have to adjust symbol tables.  The st_shndx member might
               have to be updated.  */
            if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
                || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
@@ -1206,7 +1246,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                            shdr_info[cnt].shdr.sh_info = destidx - 1;
                          }
                      }
-                   else
+                   else if (debug_fname == NULL
+                            || shdr_info[cnt].debug_data == NULL)
                      /* This is a section symbol for a section which has
                         been removed.  */
                      assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION);
@@ -1248,291 +1289,288 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
   /* Adjust symbol references if symbol tables changed.  */
   if (any_symtab_changes)
-    {
-      /* Find all relocation sections which use this
-        symbol table.  */
-      for (cnt = 1; cnt <= shdridx; ++cnt)
+    /* Find all relocation sections which use this symbol table.  */
+    for (cnt = 1; cnt <= shdridx; ++cnt)
+      {
+       /* Update section headers when the data size has changed.
+          We also update the SHT_NOBITS section in the debug
+          file so that the section headers match in sh_size.  */
+       inline void update_section_size (const Elf_Data *newdata)
        {
-         /* Update section headers when the data size has changed.
-            We also update the SHT_NOBITS section in the debug
-            file so that the section headers match in sh_size.  */
-         inline void update_section_size (const Elf_Data *newdata)
+         GElf_Shdr shdr_mem;
+         GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+         shdr->sh_size = newdata->d_size;
+         (void) gelf_update_shdr (scn, shdr);
+         if (debugelf != NULL)
            {
-             GElf_Shdr shdr_mem;
-             GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-             shdr->sh_size = newdata->d_size;
-             (void) gelf_update_shdr (scn, shdr);
-             if (debugelf != NULL)
-               {
-                 /* libelf will use d_size to set sh_size.  */
-                 Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf,
-                                                                cnt), NULL);
-                 debugdata->d_size = newdata->d_size;
-               }
+             /* libelf will use d_size to set sh_size.  */
+             Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf,
+                                                            cnt), NULL);
+             debugdata->d_size = newdata->d_size;
            }
+       }
 
-         if (shdr_info[cnt].idx == 0 && debug_fname == NULL)
-           /* Ignore sections which are discarded.  When we are saving a
-              relocation section in a separate debug file, we must fix up
-              the symbol table references.  */
-           continue;
+       if (shdr_info[cnt].idx == 0 && debug_fname == NULL)
+         /* Ignore sections which are discarded.  When we are saving a
+            relocation section in a separate debug file, we must fix up
+            the symbol table references.  */
+         continue;
 
-         if (shdr_info[cnt].shdr.sh_type == SHT_REL
-             || shdr_info[cnt].shdr.sh_type == SHT_RELA)
+       const Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
+       const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx;
+       switch (shdr_info[cnt].shdr.sh_type)
+         {
+           inline bool no_symtab_updates (void)
            {
              /* If the symbol table hasn't changed, do not do anything.  */
-             if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL)
-               continue;
-
-             Elf32_Word *newsymidx
-               = shdr_info[shdr_info[cnt].old_sh_link].newsymidx;
-             Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0
-                                        ? elf_getscn (debugelf, cnt)
-                                        : elf_getscn (newelf,
-                                                      shdr_info[cnt].idx),
-                                        NULL);
-             assert (d != NULL);
-             size_t nrels = (shdr_info[cnt].shdr.sh_size
-                             / shdr_info[cnt].shdr.sh_entsize);
-
-             if (shdr_info[cnt].shdr.sh_type == SHT_REL)
-               for (size_t relidx = 0; relidx < nrels; ++relidx)
-                 {
-                   GElf_Rel rel_mem;
-                   if (gelf_getrel (d, relidx, &rel_mem) == NULL)
-                     INTERNAL_ERROR (fname);
+             if (shdr_info[symtabidx].newsymidx == NULL)
+               return true;
 
-                   size_t symidx = GELF_R_SYM (rel_mem.r_info);
-                   if (newsymidx[symidx] != symidx)
-                     {
-                       rel_mem.r_info
-                         = GELF_R_INFO (newsymidx[symidx],
-                                        GELF_R_TYPE (rel_mem.r_info));
+             /* If the symbol table is not discarded, but additionally
+                duplicated in the separate debug file and this section
+                is discarded, don't adjust anything.  */
+             return (shdr_info[cnt].idx == 0
+                     && shdr_info[symtabidx].debug_data != NULL);
+           }
 
-                       if (gelf_update_rel (d, relidx, &rel_mem) == 0)
-                         INTERNAL_ERROR (fname);
-                     }
-                 }
-             else
-               for (size_t relidx = 0; relidx < nrels; ++relidx)
-                 {
-                   GElf_Rela rel_mem;
-                   if (gelf_getrela (d, relidx, &rel_mem) == NULL)
-                     INTERNAL_ERROR (fname);
+         case SHT_REL:
+         case SHT_RELA:
+           if (no_symtab_updates ())
+             break;
 
-                   size_t symidx = GELF_R_SYM (rel_mem.r_info);
-                   if (newsymidx[symidx] != symidx)
-                     {
-                       rel_mem.r_info
-                         = GELF_R_INFO (newsymidx[symidx],
-                                        GELF_R_TYPE (rel_mem.r_info));
+           Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0
+                                      ? elf_getscn (debugelf, cnt)
+                                      : elf_getscn (newelf,
+                                                    shdr_info[cnt].idx),
+                                      NULL);
+           assert (d != NULL);
+           size_t nrels = (shdr_info[cnt].shdr.sh_size
+                           / shdr_info[cnt].shdr.sh_entsize);
 
-                       if (gelf_update_rela (d, relidx, &rel_mem) == 0)
-                         INTERNAL_ERROR (fname);
-                     }
-                 }
-           }
-         else if (shdr_info[cnt].shdr.sh_type == SHT_HASH)
-           {
-             /* We have to recompute the hash table.  */
-             Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
+           if (shdr_info[cnt].shdr.sh_type == SHT_REL)
+             for (size_t relidx = 0; relidx < nrels; ++relidx)
+               {
+                 GElf_Rel rel_mem;
+                 if (gelf_getrel (d, relidx, &rel_mem) == NULL)
+                   INTERNAL_ERROR (fname);
 
-             /* We do not have to do anything if the symbol table was
-                not changed.  */
-             if (shdr_info[symtabidx].newsymidx == NULL)
-               continue;
+                 size_t symidx = GELF_R_SYM (rel_mem.r_info);
+                 if (newsymidx[symidx] != symidx)
+                   {
+                     rel_mem.r_info
+                       = GELF_R_INFO (newsymidx[symidx],
+                                      GELF_R_TYPE (rel_mem.r_info));
 
-             assert (shdr_info[cnt].idx > 0);
+                     if (gelf_update_rel (d, relidx, &rel_mem) == 0)
+                       INTERNAL_ERROR (fname);
+                   }
+               }
+           else
+             for (size_t relidx = 0; relidx < nrels; ++relidx)
+               {
+                 GElf_Rela rel_mem;
+                 if (gelf_getrela (d, relidx, &rel_mem) == NULL)
+                   INTERNAL_ERROR (fname);
 
-             /* The hash section in the new file.  */
-             scn = elf_getscn (newelf, shdr_info[cnt].idx);
+                 size_t symidx = GELF_R_SYM (rel_mem.r_info);
+                 if (newsymidx[symidx] != symidx)
+                   {
+                     rel_mem.r_info
+                       = GELF_R_INFO (newsymidx[symidx],
+                                      GELF_R_TYPE (rel_mem.r_info));
 
-             /* The symbol table data.  */
-             Elf_Data *symd = elf_getdata (elf_getscn (newelf,
-                                                       shdr_info[symtabidx].idx),
-                                           NULL);
-             assert (symd != NULL);
+                     if (gelf_update_rela (d, relidx, &rel_mem) == 0)
+                       INTERNAL_ERROR (fname);
+                   }
+               }
+           break;
 
-             /* The hash table data.  */
-             Elf_Data *hashd = elf_getdata (scn, NULL);
-             assert (hashd != NULL);
+         case SHT_HASH:
+           if (no_symtab_updates ())
+             break;
 
-             if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word))
-               {
-                 /* Sane arches first.  */
-                 Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf;
+           /* We have to recompute the hash table.  */
 
-                 size_t strshndx = shdr_info[symtabidx].old_sh_link;
-                 size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1,
-                                             ehdr->e_version);
+           assert (shdr_info[cnt].idx > 0);
 
-                 /* Adjust the nchain value.  The symbol table size
-                    changed.  We keep the same size for the bucket array.  */
-                 bucket[1] = symd->d_size / elsize;
-                 Elf32_Word nbucket = bucket[0];
-                 bucket += 2;
-                 Elf32_Word *chain = bucket + nbucket;
-
-                 /* New size of the section.  */
-                 hashd->d_size = ((2 + symd->d_size / elsize + nbucket)
-                                  * sizeof (Elf32_Word));
-                 update_section_size (hashd);
-
-                 /* Clear the arrays.  */
-                 memset (bucket, '\0',
-                         (symd->d_size / elsize + nbucket)
-                         * sizeof (Elf32_Word));
-
-                 for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
-                      inner < symd->d_size / elsize; ++inner)
-                   {
-                     GElf_Sym sym_mem;
-                     GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
-                     assert (sym != NULL);
+           /* The hash section in the new file.  */
+           scn = elf_getscn (newelf, shdr_info[cnt].idx);
 
-                     const char *name = elf_strptr (elf, strshndx,
-                                                    sym->st_name);
-                     assert (name != NULL);
-                     size_t hidx = elf_hash (name) % nbucket;
+           /* The symbol table data.  */
+           Elf_Data *symd = elf_getdata (elf_getscn (newelf,
+                                                     shdr_info[symtabidx].idx),
+                                         NULL);
+           assert (symd != NULL);
 
-                     if (bucket[hidx] == 0)
-                       bucket[hidx] = inner;
-                     else
-                       {
-                         hidx = bucket[hidx];
+           /* The hash table data.  */
+           Elf_Data *hashd = elf_getdata (scn, NULL);
+           assert (hashd != NULL);
 
-                         while (chain[hidx] != 0)
-                           hidx = chain[hidx];
+           if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word))
+             {
+               /* Sane arches first.  */
+               Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf;
 
-                         chain[hidx] = inner;
-                       }
-                   }
-               }
-             else
-               {
-                 /* Alpha and S390 64-bit use 64-bit SHT_HASH entries.  */
-                 assert (shdr_info[cnt].shdr.sh_entsize
-                         == sizeof (Elf64_Xword));
+               size_t strshndx = shdr_info[symtabidx].old_sh_link;
+               size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1,
+                                           ehdr->e_version);
 
-                 Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf;
+               /* Adjust the nchain value.  The symbol table size
+                  changed.  We keep the same size for the bucket array.  */
+               bucket[1] = symd->d_size / elsize;
+               Elf32_Word nbucket = bucket[0];
+               bucket += 2;
+               Elf32_Word *chain = bucket + nbucket;
+
+               /* New size of the section.  */
+               hashd->d_size = ((2 + symd->d_size / elsize + nbucket)
+                                * sizeof (Elf32_Word));
+               update_section_size (hashd);
+
+               /* Clear the arrays.  */
+               memset (bucket, '\0',
+                       (symd->d_size / elsize + nbucket)
+                       * sizeof (Elf32_Word));
+
+               for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
+                    inner < symd->d_size / elsize; ++inner)
+                 {
+                   GElf_Sym sym_mem;
+                   GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
+                   assert (sym != NULL);
 
-                 size_t strshndx = shdr_info[symtabidx].old_sh_link;
-                 size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1,
-                                             ehdr->e_version);
+                   const char *name = elf_strptr (elf, strshndx,
+                                                  sym->st_name);
+                   assert (name != NULL);
+                   size_t hidx = elf_hash (name) % nbucket;
 
-                 /* Adjust the nchain value.  The symbol table size
-                    changed.  We keep the same size for the bucket array.  */
-                 bucket[1] = symd->d_size / elsize;
-                 Elf64_Xword nbucket = bucket[0];
-                 bucket += 2;
-                 Elf64_Xword *chain = bucket + nbucket;
-
-                 /* New size of the section.  */
-                 hashd->d_size = ((2 + symd->d_size / elsize + nbucket)
-                                  * sizeof (Elf64_Xword));
-                 update_section_size (hashd);
-
-                 /* Clear the arrays.  */
-                 memset (bucket, '\0',
-                         (symd->d_size / elsize + nbucket)
-                         * sizeof (Elf64_Xword));
-
-                 for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
-                      inner < symd->d_size / elsize; ++inner)
-                   {
-                     GElf_Sym sym_mem;
-                     GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
-                     assert (sym != NULL);
+                   if (bucket[hidx] == 0)
+                     bucket[hidx] = inner;
+                   else
+                     {
+                       hidx = bucket[hidx];
 
-                     const char *name = elf_strptr (elf, strshndx,
-                                                    sym->st_name);
-                     assert (name != NULL);
-                     size_t hidx = elf_hash (name) % nbucket;
+                       while (chain[hidx] != 0)
+                         hidx = chain[hidx];
 
-                     if (bucket[hidx] == 0)
-                       bucket[hidx] = inner;
-                     else
-                       {
-                         hidx = bucket[hidx];
+                       chain[hidx] = inner;
+                     }
+                 }
+             }
+           else
+             {
+               /* Alpha and S390 64-bit use 64-bit SHT_HASH entries.  */
+               assert (shdr_info[cnt].shdr.sh_entsize
+                       == sizeof (Elf64_Xword));
 
-                         while (chain[hidx] != 0)
-                           hidx = chain[hidx];
+               Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf;
 
-                         chain[hidx] = inner;
-                       }
-                   }
-               }
-           }
-         else if (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym)
-           {
-             /* If the symbol table changed we have to adjust the
-                entries.  */
-             Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
+               size_t strshndx = shdr_info[symtabidx].old_sh_link;
+               size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1,
+                                           ehdr->e_version);
 
-             /* We do not have to do anything if the symbol table was
-                not changed.  */
-             if (shdr_info[symtabidx].newsymidx == NULL)
-               continue;
-
-             assert (shdr_info[cnt].idx > 0);
-
-             /* The symbol version section in the new file.  */
-             scn = elf_getscn (newelf, shdr_info[cnt].idx);
-
-             /* The symbol table data.  */
-             Elf_Data *symd = elf_getdata (elf_getscn (newelf,
-                                                       shdr_info[symtabidx].idx),
-                                           NULL);
-             assert (symd != NULL);
-
-             /* The version symbol data.  */
-             Elf_Data *verd = elf_getdata (scn, NULL);
-             assert (verd != NULL);
-
-             /* The symbol version array.  */
-             GElf_Half *verstab = (GElf_Half *) verd->d_buf;
-
-             /* New indices of the symbols.  */
-             Elf32_Word *newsymidx = shdr_info[symtabidx].newsymidx;
-
-             /* Walk through the list and */
-             size_t elsize = gelf_fsize (elf, verd->d_type, 1,
-                                         ehdr->e_version);
-             for (size_t inner = 1; inner < verd->d_size / elsize; ++inner)
-               if (newsymidx[inner] != 0)
-                 /* Overwriting the same array works since the
-                    reordering can only move entries to lower indices
-                    in the array.  */
-                 verstab[newsymidx[inner]] = verstab[inner];
-
-             /* New size of the section.  */
-             verd->d_size = gelf_fsize (newelf, verd->d_type,
-                                        symd->d_size
-                                        / gelf_fsize (elf, symd->d_type, 1,
-                                                      ehdr->e_version),
-                                        ehdr->e_version);
-             update_section_size (verd);
-           }
-         else if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
-           {
-             /* Check whether the associated symbol table changed.  */
-             if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx != NULL)
-               {
-                 /* Yes the symbol table changed.  Update the section
-                    header of the section group.  */
-                 scn = elf_getscn (newelf, shdr_info[cnt].idx);
-                 GElf_Shdr shdr_mem;
-                 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-                 assert (shdr != NULL);
+               /* Adjust the nchain value.  The symbol table size
+                  changed.  We keep the same size for the bucket array.  */
+               bucket[1] = symd->d_size / elsize;
+               Elf64_Xword nbucket = bucket[0];
+               bucket += 2;
+               Elf64_Xword *chain = bucket + nbucket;
+
+               /* New size of the section.  */
+               hashd->d_size = ((2 + symd->d_size / elsize + nbucket)
+                                * sizeof (Elf64_Xword));
+               update_section_size (hashd);
+
+               /* Clear the arrays.  */
+               memset (bucket, '\0',
+                       (symd->d_size / elsize + nbucket)
+                       * sizeof (Elf64_Xword));
+
+               for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
+                    inner < symd->d_size / elsize; ++inner)
+                 {
+                   GElf_Sym sym_mem;
+                   GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
+                   assert (sym != NULL);
 
-                 size_t stabidx = shdr_info[cnt].old_sh_link;
-                 shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info];
+                   const char *name = elf_strptr (elf, strshndx,
+                                                  sym->st_name);
+                   assert (name != NULL);
+                   size_t hidx = elf_hash (name) % nbucket;
 
-                 (void) gelf_update_shdr (scn, shdr);
-               }
-           }
-       }
-    }
+                   if (bucket[hidx] == 0)
+                     bucket[hidx] = inner;
+                   else
+                     {
+                       hidx = bucket[hidx];
+
+                       while (chain[hidx] != 0)
+                         hidx = chain[hidx];
+
+                       chain[hidx] = inner;
+                     }
+                 }
+             }
+           break;
+
+         case SHT_GNU_versym:
+           /* If the symbol table changed we have to adjust the entries.  */
+           if (no_symtab_updates ())
+             break;
+
+           assert (shdr_info[cnt].idx > 0);
+
+           /* The symbol version section in the new file.  */
+           scn = elf_getscn (newelf, shdr_info[cnt].idx);
+
+           /* The symbol table data.  */
+           symd = elf_getdata (elf_getscn (newelf, shdr_info[symtabidx].idx),
+                               NULL);
+           assert (symd != NULL);
+
+           /* The version symbol data.  */
+           Elf_Data *verd = elf_getdata (scn, NULL);
+           assert (verd != NULL);
+
+           /* The symbol version array.  */
+           GElf_Half *verstab = (GElf_Half *) verd->d_buf;
+
+           /* Walk through the list and */
+           size_t elsize = gelf_fsize (elf, verd->d_type, 1,
+                                       ehdr->e_version);
+           for (size_t inner = 1; inner < verd->d_size / elsize; ++inner)
+             if (newsymidx[inner] != 0)
+               /* Overwriting the same array works since the
+                  reordering can only move entries to lower indices
+                  in the array.  */
+               verstab[newsymidx[inner]] = verstab[inner];
+
+           /* New size of the section.  */
+           verd->d_size = gelf_fsize (newelf, verd->d_type,
+                                      symd->d_size
+                                      / gelf_fsize (elf, symd->d_type, 1,
+                                                    ehdr->e_version),
+                                      ehdr->e_version);
+           update_section_size (verd);
+           break;
+
+         case SHT_GROUP:
+           if (no_symtab_updates ())
+             break;
+
+           /* Yes, the symbol table changed.
+              Update the section header of the section group.  */
+           scn = elf_getscn (newelf, shdr_info[cnt].idx);
+           GElf_Shdr shdr_mem;
+           GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+           assert (shdr != NULL);
+
+           shdr->sh_info = newsymidx[shdr->sh_info];
+
+           (void) gelf_update_shdr (scn, shdr);
+           break;
+         }
+      }
 
   /* Now that we have done all adjustments to the data,
      we can actually write out the debug file.  */
@@ -1659,7 +1697,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
         table indices.  */
       if (any_symtab_changes)
        for (cnt = 1; cnt <= shdridx; ++cnt)
-         free (shdr_info[cnt].newsymidx);
+         {
+           free (shdr_info[cnt].newsymidx);
+           if (shdr_info[cnt].debug_data != NULL)
+             free (shdr_info[cnt].debug_data->d_buf);
+         }
 
       /* Free the memory.  */
       if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
index d9d7469217d114b0fc497408d70deace3819fae8..c9bba45cc97f9a67e976f1c1b52a8f2fe051fc79 100644 (file)
@@ -1,3 +1,16 @@
+2008-04-10  Roland McGrath  <roland@redhat.com>
+
+       * testfile48.bz2, testfile48.bz2.debug: New data files.
+       * Makefile.am (EXTRA_DIST): Add them.
+       * run-strip-test8.sh: Use them.
+
+       * testfile16.bz2, testfile16.debug.bz2: Replace data files.
+
+       * run-strip-test.sh: Fail if stripped output has ".debug_*" sections.
+       * run-strip-test8.sh: New file.
+       * testfile47.bz2: New data file.
+       * Makefile.am (TESTS, EXTRA_DIST): Add them.
+
 2008-03-31  Roland McGrath  <roland@redhat.com>
 
        * run-early-offscn.sh: New file.
index f0b20e9dc2eb745aadc83e810764d9df81e3ca86..361c6581bb3d77fd53f2503e455b947dd55f287c 100644 (file)
@@ -71,7 +71,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-show-abbrev.sh run-line2addr.sh hash \
        newscn run-strip-test.sh run-strip-test2.sh \
        run-strip-test3.sh run-strip-test4.sh run-strip-test5.sh \
-       run-strip-test6.sh run-strip-test7.sh \
+       run-strip-test6.sh run-strip-test7.sh run-strip-test8.sh \
        run-unstrip-test.sh run-unstrip-test2.sh \
        run-ecp-test.sh run-ecp-test2.sh \
        run-elflint-test.sh run-elflint-self.sh run-ranlib-test.sh \
@@ -110,7 +110,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile13.bz2 run-strip-test3.sh run-allfcts.sh \
             run-line2addr.sh run-elflint-test.sh testfile14.bz2 \
             run-strip-test4.sh run-strip-test5.sh run-strip-test6.sh \
-            run-strip-test7.sh run-unstrip-test.sh run-unstrip-test2.sh \
+            run-strip-test7.sh run-strip-test8.sh \
+            run-unstrip-test.sh run-unstrip-test2.sh \
             run-elflint-self.sh run-ranlib-test.sh run-ranlib-test2.sh \
             run-ranlib-test3.sh run-ranlib-test4.sh \
             run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
@@ -138,7 +139,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile41.bz2 testfile42.bz2 testfile43.bz2 \
             testfile44.S.bz2 testfile44.expect.bz2 run-disasm-x86.sh \
             testfile45.S.bz2 testfile45.expect.bz2 run-disasm-x86-64.sh \
-            testfile46.bz2
+            testfile46.bz2 testfile47.bz2 testfile48.bz2 testfile48.debug.bz2
 
 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
                              bindir=$(DESTDIR)$(bindir) \
index 480101ebd9a97775b3379bafbf2eefaeae261476..e056f8904d0a42869be07429352175f3401882c5 100755 (executable)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 1999, 2000, 2002, 2003, 2005, 2007 Red Hat, Inc.
+# Copyright (C) 1999, 2000, 2002, 2003, 2005, 2007, 2008 Red Hat, Inc.
 # This file is part of Red Hat elfutils.
 # Written by Ulrich Drepper <drepper@redhat.com>, 1999.
 #
@@ -30,7 +30,8 @@ original=${original:-testfile11}
 stripped=${stripped:-testfile7}
 debugout=${debugfile:+-f testfile.debug.temp -F $debugfile}
 
-testfiles $original $stripped $debugfile
+testfiles $original
+test x$stripped = xtestfile.temp || testfiles $stripped $debugfile
 
 tempfiles testfile.temp testfile.debug.temp testfile.unstrip
 
@@ -56,4 +57,8 @@ testrun ../src/unstrip -o testfile.unstrip testfile.temp testfile.debug.temp
 testrun ../src/elfcmp --hash-inexact $original testfile.unstrip
 }
 
+tempfiles testfile.sections
+testrun ../src/readelf -S testfile.temp > testfile.sections || status=$?
+fgrep ' .debug_' testfile.sections && status=1
+
 exit $status
diff --git a/tests/run-strip-test8.sh b/tests/run-strip-test8.sh
new file mode 100755 (executable)
index 0000000..fb9fa08
--- /dev/null
@@ -0,0 +1,5 @@
+original=testfile47
+stripped=testfile48
+debugfile=testfile48.debug
+
+. $srcdir/run-strip-test.sh
index 909e2253baec7e97c807d27bc97e1af21c91dc55..4d7160c0c5d2d6b54862fcd95baa09d0ccecf731 100644 (file)
Binary files a/tests/testfile16.bz2 and b/tests/testfile16.bz2 differ
index 48d651fbbfbb7e40696cb832d33d886e5d0e56db..f02a9723665182477d4a9a87ad6dd7193835dc8b 100644 (file)
Binary files a/tests/testfile16.debug.bz2 and b/tests/testfile16.debug.bz2 differ
diff --git a/tests/testfile47.bz2 b/tests/testfile47.bz2
new file mode 100644 (file)
index 0000000..334bd6c
Binary files /dev/null and b/tests/testfile47.bz2 differ
diff --git a/tests/testfile48.bz2 b/tests/testfile48.bz2
new file mode 100644 (file)
index 0000000..da0d9da
Binary files /dev/null and b/tests/testfile48.bz2 differ
diff --git a/tests/testfile48.debug.bz2 b/tests/testfile48.debug.bz2
new file mode 100644 (file)
index 0000000..7b84c4c
Binary files /dev/null and b/tests/testfile48.debug.bz2 differ