diff options
-rw-r--r-- | src/ChangeLog | 19 | ||||
-rw-r--r-- | src/elflint.c | 13 | ||||
-rw-r--r-- | src/strip.c | 568 | ||||
-rw-r--r-- | tests/ChangeLog | 13 | ||||
-rw-r--r-- | tests/Makefile.am | 7 | ||||
-rwxr-xr-x | tests/run-strip-test.sh | 9 | ||||
-rwxr-xr-x | tests/run-strip-test8.sh | 5 | ||||
-rw-r--r-- | tests/testfile16.bz2 | bin | 8424 -> 8413 bytes | |||
-rw-r--r-- | tests/testfile16.debug.bz2 | bin | 23520 -> 24257 bytes | |||
-rw-r--r-- | tests/testfile47.bz2 | bin | 0 -> 793 bytes | |||
-rw-r--r-- | tests/testfile48.bz2 | bin | 0 -> 408 bytes | |||
-rw-r--r-- | tests/testfile48.debug.bz2 | bin | 0 -> 758 bytes |
12 files changed, 362 insertions, 272 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 41267ea0..94444c58 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -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: diff --git a/src/elflint.c b/src/elflint.c index b13dfdb5..bc4219b3 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -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); diff --git a/src/strip.c b/src/strip.c index 5fddeeeb..0f83e61d 100644 --- a/src/strip.c +++ b/src/strip.c @@ -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) diff --git a/tests/ChangeLog b/tests/ChangeLog index d9d74692..c9bba45c 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -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. diff --git a/tests/Makefile.am b/tests/Makefile.am index f0b20e9d..361c6581 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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) \ diff --git a/tests/run-strip-test.sh b/tests/run-strip-test.sh index 480101eb..e056f890 100755 --- a/tests/run-strip-test.sh +++ b/tests/run-strip-test.sh @@ -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 index 00000000..fb9fa087 --- /dev/null +++ b/tests/run-strip-test8.sh @@ -0,0 +1,5 @@ +original=testfile47 +stripped=testfile48 +debugfile=testfile48.debug + +. $srcdir/run-strip-test.sh diff --git a/tests/testfile16.bz2 b/tests/testfile16.bz2 Binary files differindex 909e2253..4d7160c0 100644 --- a/tests/testfile16.bz2 +++ b/tests/testfile16.bz2 diff --git a/tests/testfile16.debug.bz2 b/tests/testfile16.debug.bz2 Binary files differindex 48d651fb..f02a9723 100644 --- a/tests/testfile16.debug.bz2 +++ b/tests/testfile16.debug.bz2 diff --git a/tests/testfile47.bz2 b/tests/testfile47.bz2 Binary files differnew file mode 100644 index 00000000..334bd6c4 --- /dev/null +++ b/tests/testfile47.bz2 diff --git a/tests/testfile48.bz2 b/tests/testfile48.bz2 Binary files differnew file mode 100644 index 00000000..da0d9dab --- /dev/null +++ b/tests/testfile48.bz2 diff --git a/tests/testfile48.debug.bz2 b/tests/testfile48.debug.bz2 Binary files differnew file mode 100644 index 00000000..7b84c4ca --- /dev/null +++ b/tests/testfile48.debug.bz2 |