2006-09-19 Jakub Jelinek * strip.c (handle_elf): Formatting. If any relocation sections stripped into separate debug info reference symtab that is kept, emit symtab/strtab also into the separate debug info file. --- elfutils/src/strip.c +++ elfutils/src/strip.c @@ -399,6 +399,7 @@ handle_elf (int fd, Elf *elf, const char Elf_Scn *newscn; struct Ebl_Strent *se; Elf32_Word *newsymidx; + void *debug_data; } *shdr_info = NULL; Elf_Scn *scn; size_t cnt; @@ -826,6 +827,37 @@ handle_elf (int fd, Elf *elf, const char The ones that are not removed in the stripped file are SHT_NOBITS. */ if (debug_fname != NULL) { + /* libbfd and apps using it don't cope with separate debuginfo objects + with relocation sections against SHT_NOBITS .symtab/.strtab + - libbfd isn't able to look up the .symtab/.strtab in the stripped + object instead. As a workaround, emit .symtab/.strtab in both + places. */ + for (cnt = 1; cnt < shnum; ++cnt) + { + if (shdr_info[cnt].idx == 0 + && (shdr_info[cnt].shdr.sh_type == SHT_REL + || shdr_info[cnt].shdr.sh_type == SHT_RELA) + && (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) + { + Elf32_Word symtabidx = shdr_info[cnt].old_sh_link; + struct shdr_info *si = &shdr_info[symtabidx]; + si->debug_data = ""; + shdr_info[si->old_sh_link].debug_data = ""; + if (si->symtab_idx) + shdr_info[si->symtab_idx].debug_data = ""; + + if (si->shdr.sh_type != SHT_SYMTAB + || (si->shdr.sh_flags & SHF_ALLOC) + || shdr_info[si->old_sh_link].shdr.sh_type != SHT_STRTAB + || (shdr_info[si->old_sh_link].shdr.sh_flags & SHF_ALLOC) + || (si->symtab_idx + && (shdr_info[si->symtab_idx].shdr.sh_flags + & SHF_ALLOC))) + error (EXIT_FAILURE, 0, + gettext ("invalid symtab/strtab referenced by nonallocated section")); + } + } + for (cnt = 1; cnt < shnum; ++cnt) { scn = elf_newscn (debugelf); @@ -835,6 +867,7 @@ handle_elf (int fd, Elf *elf, const char 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); @@ -865,6 +898,13 @@ handle_elf (int fd, Elf *elf, const char *debugdata = *shdr_info[cnt].data; if (discard_section) debugdata->d_buf = NULL; + else if (shdr_info[cnt].debug_data != NULL) + { + shdr_info[cnt].debug_data = xmalloc (debugdata->d_size); + memcpy (shdr_info[cnt].debug_data, debugdata->d_buf, + debugdata->d_size); + debugdata->d_buf = shdr_info[cnt].debug_data; + } } /* Finish the ELF header. Fill in the fields not handled by @@ -1056,7 +1096,7 @@ handle_elf (int fd, Elf *elf, const char shdr_info[shdr_info[cnt].shdr.sh_info].idx; /* Get the data from the old file if necessary. We already - created the data for the section header string table. */ + created the data for the section header string table. */ if (cnt < shnum) { if (shdr_info[cnt].data == NULL) @@ -1283,6 +1323,13 @@ handle_elf (int fd, Elf *elf, const char if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL) continue; + /* If the symbol table is not discarded, but additionally + duplicated in separate debug file and this section + is discarded, don't adjust anything. */ + if (shdr_info[cnt].idx == 0 + && shdr_info[shdr_info[cnt].old_sh_link].debug_data != NULL) + continue; + Elf32_Word *newsymidx = shdr_info[shdr_info[cnt].old_sh_link].newsymidx; Elf_Data *d = elf_getdata (shdr_info[cnt].idx == 0 @@ -1341,6 +1388,13 @@ handle_elf (int fd, Elf *elf, const char if (shdr_info[symtabidx].newsymidx == NULL) continue; + /* If the symbol table is not discarded, but additionally + duplicated in separate debug file and this section + is discarded, don't adjust anything. */ + if (shdr_info[cnt].idx == 0 + && shdr_info[symtabidx].debug_data != NULL) + continue; + assert (shdr_info[cnt].idx > 0); /* The hash section in the new file. */ @@ -1460,7 +1514,7 @@ handle_elf (int fd, Elf *elf, const char chain[hidx] = inner; } } - } + } } else if (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym) { @@ -1473,6 +1527,13 @@ handle_elf (int fd, Elf *elf, const char if (shdr_info[symtabidx].newsymidx == NULL) continue; + /* If the symbol table is not discarded, but additionally + duplicated in separate debug file and this section + is discarded, don't adjust anything. */ + if (shdr_info[cnt].idx == 0 + && shdr_info[symtabidx].debug_data != NULL) + continue; + assert (shdr_info[cnt].idx > 0); /* The symbol version section in the new file. */ @@ -1515,20 +1576,27 @@ handle_elf (int fd, Elf *elf, const char 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); + if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL) + continue; - size_t stabidx = shdr_info[cnt].old_sh_link; - shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info]; + /* If the symbol table is not discarded, but additionally + duplicated in separate debug file and this section + is discarded, don't adjust anything. */ + if (shdr_info[cnt].idx == 0 + && shdr_info[shdr_info[cnt].old_sh_link].debug_data != NULL) + continue; - (void) gelf_update_shdr (scn, shdr); - } + /* 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); + + size_t stabidx = shdr_info[cnt].old_sh_link; + shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info]; + + (void) gelf_update_shdr (scn, shdr); } } } @@ -1658,7 +1726,10 @@ handle_elf (int fd, Elf *elf, const char table indices. */ if (any_symtab_changes) for (cnt = 1; cnt <= shdridx; ++cnt) - free (shdr_info[cnt].newsymidx); + { + free (shdr_info[cnt].newsymidx); + free (shdr_info[cnt].debug_data); + } /* Free the memory. */ if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC) --- elfutils/tests/run-strip-test5.sh.~1~ +++ elfutils/tests/run-strip-test5.sh @@ -1,5 +1,5 @@ original=testfile8 -stripped=testfile16 -debugfile=testfile16.debug +stripped=testfile16.symtab +debugfile=testfile16.symtab.debug . $srcdir/run-strip-test.sh